523 prev next chunks index CyanogenMod/android_packages_apps_Trebuchet_d223b88f0dbff7cd66876e691345df5c1ede242b_src/com/android/launcher3/Workspace.java {strict: [[b]], subset: [[b]]}
line based (standard git) jfstmerge spork
   1 /*                                                                                                       
   2  * Copyright (C) 2008 The Android Open Source Project                                                    
   3  *                                                                                                       
   4  * Licensed under the Apache License, Version 2.0 (the "License");                                       
   5  * you may not use this file except in compliance with the License.                                      
   6  * You may obtain a copy of the License at                                                               
   7  *                                                                                                       
   8  *      http://www.apache.org/licenses/LICENSE-2.0                                                       
   9  *                                                                                                       
  10  * Unless required by applicable law or agreed to in writing, software                                   
  11  * distributed under the License is distributed on an "AS IS" BASIS,                                     
  12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.                              
  13  * See the License for the specific language governing permissions and                                   
  14  * limitations under the License.                                                                        
  15  */                                                                                                      
  16                                                                                                          
  17 package com.android.launcher3;                                                                           
  18                                                                                                          
  19 import android.animation.Animator;                                                                       
  20 import android.animation.Animator.AnimatorListener;                                                      
  21 import android.animation.AnimatorListenerAdapter;                                                        
  22 import android.animation.AnimatorSet;                                                                    
  23 import android.animation.LayoutTransition;                                                               
  24 import android.animation.ObjectAnimator;                                                                 
  25 import android.animation.PropertyValuesHolder;                                                           
  26 import android.animation.TimeInterpolator;                                                               
  27 import android.animation.ValueAnimator;                                                                  
  28 import android.animation.ValueAnimator.AnimatorUpdateListener;                                           
  29 import android.app.WallpaperManager;                                                                     
  30 import android.appwidget.AppWidgetHostView;                                                              
  31 import android.appwidget.AppWidgetProviderInfo;                                                          
  32 import android.content.ComponentName;                                                                    
  33 import android.content.Context;                                                                          
  34 import android.content.Intent;                                                                           
  35 import android.content.SharedPreferences;                                                                
  36 import android.content.pm.PackageManager;                                                                
  37 import android.content.pm.ResolveInfo;                                                                   
  38 import android.content.res.Resources;                                                                    
  39 import android.content.res.TypedArray;                                                                   
  40 import android.graphics.Bitmap;                                                                          
  41 import android.graphics.Canvas;                                                                          
  42 import android.graphics.Matrix;                                                                          
  43 import android.graphics.Paint;                                                                           
  44 import android.graphics.Point;                                                                           
  45 import android.graphics.PointF;                                                                          
  46 import android.graphics.Rect;                                                                            
  47 import android.graphics.Region.Op;                                                                       
  48 import android.graphics.drawable.Drawable;                                                               
  49 import android.net.Uri;                                                                                  
  50 import android.os.AsyncTask;                                                                             
  51 import android.os.Handler;                                                                               
  52 import android.os.IBinder;                                                                               
  53 import android.os.Parcelable;                                                                            
  54 import android.support.v4.view.ViewCompat;                                                               
  55 import android.util.AttributeSet;                                                                        
  56 import android.util.Log;                                                                                 
  57 import android.util.SparseArray;                                                                         
  58 import android.view.Choreographer;                                                                       
  59 import android.view.Display;                                                                             
  60 import android.view.MotionEvent;                                                                         
  61 import android.view.View;                                                                                
  62 import android.view.ViewGroup;                                                                           
  63 import android.view.accessibility.AccessibilityManager;                                                  
  64 import android.view.animation.DecelerateInterpolator;                                                    
  65 import android.view.animation.Interpolator;                                                              
  66 import android.widget.TextView;                                                                          
  67                                                                                                          
  68 import com.android.launcher3.FolderIcon.FolderRingAnimator;                                              
  69 import com.android.launcher3.Launcher.CustomContentCallbacks;                                            
  70 import com.android.launcher3.LauncherSettings.Favorites;                                                 
  71 import com.android.launcher3.compat.PackageInstallerCompat;                                              
  72 import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;                           
  73 import com.android.launcher3.compat.UserHandleCompat;                                                    
  74                                                                                                          
  75 import java.util.ArrayList;                                                                              
  76 import java.util.HashMap;                                                                                
  77 import java.util.HashSet;                                                                                
  78 import java.util.Iterator;                                                                               
  79 import java.util.Map;                                                                                    
  80 import java.util.Set;                                                                                    
  81 import java.util.concurrent.atomic.AtomicInteger;                                                        
  82                                                                                                          
  83 /**                                                                                                      
  84  * The workspace is a wide area with a wallpaper and a finite number of pages.                           
  85  * Each page contains a number of icons, folders or widgets the user can                                 
  86  * interact with. A workspace is meant to be used with a fixed width only.                               
  87  */                                                                                                      
  88 public class Workspace extends SmoothPagedView                                                           
  89         implements DropTarget, DragSource, DragScroller, View.OnTouchListener,                           
  90         DragController.DragListener, LauncherTransitionable, ViewGroup.OnHierarchyChangeListener,        
  91         Insettable {                                                                                     
  92     private static final String TAG = "Launcher.Workspace";                                              
  93                                                                                                          
  94     // Y rotation to apply to the workspace screens                                                      
  95     private static final float WORKSPACE_OVERSCROLL_ROTATION = 24f;                                      
  96                                                                                                          
  97     private static final int CHILDREN_OUTLINE_FADE_OUT_DELAY = 0;                                        
  98     private static final int CHILDREN_OUTLINE_FADE_OUT_DURATION = 375;                                   
  99     private static final int CHILDREN_OUTLINE_FADE_IN_DURATION = 100;                                    
 100                                                                                                          
 101     protected static final int SNAP_OFF_EMPTY_SCREEN_DURATION = 400;                                     
 102     protected static final int FADE_EMPTY_SCREEN_DURATION = 150;                                         
 103                                                                                                          
 104     private static final int BACKGROUND_FADE_OUT_DURATION = 350;                                         
 105     private static final int ADJACENT_SCREEN_DROP_DURATION = 300;                                        
 106     private static final int FLING_THRESHOLD_VELOCITY = 500;                                             
 107                                                                                                          
 108     private static final float ALPHA_CUTOFF_THRESHOLD = 0.01f;                                           
 109                                                                                                          
 110     static final boolean MAP_NO_RECURSE = false;                                                         
 111     static final boolean MAP_RECURSE = true;                                                             
 112                                                                                                          
 113     // These animators are used to fade the children's outlines                                          
 114     private ObjectAnimator mChildrenOutlineFadeInAnimation;                                              
 115     private ObjectAnimator mChildrenOutlineFadeOutAnimation;                                             
 116     private float mChildrenOutlineAlpha = 0;                                                             
 117                                                                                                          
 118     // These properties refer to the background protection gradient used for AllApps and Customize       
 119     private ValueAnimator mBackgroundFadeInAnimation;                                                    
 120     private ValueAnimator mBackgroundFadeOutAnimation;                                                   
 121                                                                                                          
 122     private static final long CUSTOM_CONTENT_GESTURE_DELAY = 200;                                        
 123     private long mTouchDownTime = -1;                                                                    
 124     private long mCustomContentShowTime = -1;                                                            
 125                                                                                                          
 126     private LayoutTransition mLayoutTransition;                                                          
 127     private final WallpaperManager mWallpaperManager;                                                    
 128     private IBinder mWindowToken;                                                                        
 129                                                                                                          
 130     private int mOriginalDefaultPage;                                                                    
 131     private int mDefaultPage;                                                                            
 132                                                                                                          
 133     private ShortcutAndWidgetContainer mDragSourceInternal;                                              
 134     private static boolean sAccessibilityEnabled;                                                        
 135                                                                                                          
 136     // The screen id used for the empty screen always present to the right.                              
 137     final static long EXTRA_EMPTY_SCREEN_ID = -201;                                                      
 138     private final static long CUSTOM_CONTENT_SCREEN_ID = -301;                                           
 139                                                                                                          
 140     private HashMap<Long, CellLayout> mWorkspaceScreens = new HashMap<Long, CellLayout>();               
 141     private ArrayList<Long> mScreenOrder = new ArrayList<Long>();                                        
 142                                                                                                          
 143     private Runnable mRemoveEmptyScreenRunnable;                                                         
 144     private boolean mDeferRemoveExtraEmptyScreen = false;                                                
 145                                                                                                          
 146     /**                                                                                                  
 147      * CellInfo for the cell that is currently being dragged                                             
 148      */                                                                                                  
 149     private CellLayout.CellInfo mDragInfo;                                                               
 150                                                                                                          
 151     /**                                                                                                  
 152      * Target drop area calculated during last acceptDrop call.                                          
 153      */                                                                                                  
 154     private int[] mTargetCell = new int[2];                                                              
 155     private int mDragOverX = -1;                                                                         
 156     private int mDragOverY = -1;                                                                         
 157                                                                                                          
 158     static Rect mLandscapeCellLayoutMetrics = null;                                                      
 159     static Rect mPortraitCellLayoutMetrics = null;                                                       
 160                                                                                                          
 161     CustomContentCallbacks mCustomContentCallbacks;                                                      
 162     boolean mCustomContentShowing;                                                                       
 163     private float mLastCustomContentScrollProgress = -1f;                                                
 164     private String mCustomContentDescription = "";                                                       
 165                                                                                                          
 166     /**                                                                                                  
 167      * The CellLayout that is currently being dragged over                                               
 168      */                                                                                                  
 169     private CellLayout mDragTargetLayout = null;                                                         
 170     /**                                                                                                  
 171      * The CellLayout that we will show as glowing                                                       
 172      */                                                                                                  
 173     private CellLayout mDragOverlappingLayout = null;                                                    
 174                                                                                                          
 175     /**                                                                                                  
 176      * The CellLayout which will be dropped to                                                           
 177      */                                                                                                  
 178     private CellLayout mDropToLayout = null;                                                             
 179                                                                                                          
 180     private Launcher mLauncher;                                                                          
 181     private IconCache mIconCache;                                                                        
 182     private DragController mDragController;                                                              
 183                                                                                                          
 184     // These are temporary variables to prevent having to allocate a new object just to                  
 185     // return an (x, y) value from helper functions. Do NOT use them to maintain other state.            
 186     private int[] mTempCell = new int[2];                                                                
 187     private int[] mTempPt = new int[2];                                                                  
 188     private int[] mTempEstimate = new int[2];                                                            
 189     private float[] mDragViewVisualCenter = new float[2];                                                
 190     private float[] mTempCellLayoutCenterCoordinates = new float[2];                                     
 191     private Matrix mTempInverseMatrix = new Matrix();                                                    
 192                                                                                                          
 193     private SpringLoadedDragController mSpringLoadedDragController;                                      
 194     private float mSpringLoadedShrinkFactor;                                                             
 195     private float mOverviewModeShrinkFactor;                                                             
 196                                                                                                          
 197     // State variable that indicates whether the pages are small (ie when you're                         
 198     // in all apps or customize mode)                                                                    
 199                                                                                                          
 200     enum State { NORMAL, NORMAL_HIDDEN, SPRING_LOADED, OVERVIEW, OVERVIEW_HIDDEN};                       
 201     private State mState = State.NORMAL;                                                                 
 202     private boolean mIsSwitchingState = false;                                                           
 203                                                                                                          
 204     boolean mAnimatingViewIntoPlace = false;                                                             
 205     boolean mIsDragOccuring = false;                                                                     
 206     boolean mChildrenLayersEnabled = true;                                                               
 207                                                                                                          
 208     private boolean mStripScreensOnPageStopMoving = false;                                               
 209                                                                                                          
 210     /** Is the user is dragging an item near the edge of a page? */                                      
 211     private boolean mInScrollArea = false;                                                               
 212                                                                                                          
 213     private HolographicOutlineHelper mOutlineHelper;                                                     
 214     private Bitmap mDragOutline = null;                                                                  
 215     private static final Rect sTempRect = new Rect();                                                    
 216     private final int[] mTempXY = new int[2];                                                            
 217     private int[] mTempVisiblePagesRange = new int[2];                                                   
 218     private boolean mOverscrollEffectSet;                                                                
 219     public static final int DRAG_BITMAP_PADDING = 2;                                                     
 220     private boolean mWorkspaceFadeInAdjacentScreens;                                                     
 221                                                                                                          
 222     WallpaperOffsetInterpolator mWallpaperOffset;                                                        
 223     private boolean mWallpaperIsLiveWallpaper;                                                           
 224     private int mNumPagesForWallpaperParallax;                                                           
 225     private float mLastSetWallpaperOffsetSteps = 0;                                                      
 226                                                                                                          
 227     private Runnable mDelayedResizeRunnable;                                                             
 228     private Runnable mDelayedSnapToPageRunnable;                                                         
 229     private Point mDisplaySize = new Point();                                                            
 230     private int mCameraDistance;                                                                         
 231                                                                                                          
 232     // Variables relating to the creation of user folders by hovering shortcuts over shortcuts           
 233     private static final int FOLDER_CREATION_TIMEOUT = 0;                                                
 234     public static final int REORDER_TIMEOUT = 350;                                                       
 235     private final Alarm mFolderCreationAlarm = new Alarm();                                              
 236     private final Alarm mReorderAlarm = new Alarm();                                                     
 237     private FolderRingAnimator mDragFolderRingAnimator = null;                                           
 238     private FolderIcon mDragOverFolderIcon = null;                                                       
 239     private boolean mCreateUserFolderOnDrop = false;                                                     
 240     private boolean mAddToExistingFolderOnDrop = false;                                                  
 241     private DropTarget.DragEnforcer mDragEnforcer;                                                       
 242     private float mMaxDistanceForFolderCreation;                                                         
 243                                                                                                          
 244     private final Canvas mCanvas = new Canvas();                                                         
 245                                                                                                          
 246     // Variables relating to touch disambiguation (scrolling workspace vs. scrolling a widget)           
 247     private float mXDown;                                                                                
 248     private float mYDown;                                                                                
 249     final static float START_DAMPING_TOUCH_SLOP_ANGLE = (float) Math.PI / 6;                             
 250     final static float MAX_SWIPE_ANGLE = (float) Math.PI / 3;                                            
 251     final static float TOUCH_SLOP_DAMPING_FACTOR = 4;                                                    
 252                                                                                                          
 253     // Relating to the animation of items being dropped externally                                       
 254     public static final int ANIMATE_INTO_POSITION_AND_DISAPPEAR = 0;                                     
 255     public static final int ANIMATE_INTO_POSITION_AND_REMAIN = 1;                                        
 256     public static final int ANIMATE_INTO_POSITION_AND_RESIZE = 2;                                        
 257     public static final int COMPLETE_TWO_STAGE_WIDGET_DROP_ANIMATION = 3;                                
 258     public static final int CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION = 4;                                  
 259                                                                                                          
 260     // Related to dragging, folder creation and reordering                                               
 261     private static final int DRAG_MODE_NONE = 0;                                                         
 262     private static final int DRAG_MODE_CREATE_FOLDER = 1;                                                
 263     private static final int DRAG_MODE_ADD_TO_FOLDER = 2;                                                
 264     private static final int DRAG_MODE_REORDER = 3;                                                      
 265     private int mDragMode = DRAG_MODE_NONE;                                                              
 266     private int mLastReorderX = -1;                                                                      
 267     private int mLastReorderY = -1;                                                                      
 268                                                                                                          
 269     private SparseArray<Parcelable> mSavedStates;                                                        
 270     private final ArrayList<Integer> mRestoredPages = new ArrayList<Integer>();                          
 271                                                                                                          
 272     // These variables are used for storing the initial and final values during workspace animations     
 273     private int mSavedScrollX;                                                                           
 274     private float mSavedRotationY;                                                                       
 275     private float mSavedTranslationX;                                                                    
 276                                                                                                          
 277     private float mCurrentScale;                                                                         
 278     private float mNewScale;                                                                             
 279     private float[] mOldBackgroundAlphas;                                                                
 280     private float[] mOldAlphas;                                                                          
 281     private float[] mNewBackgroundAlphas;                                                                
 282     private float[] mNewAlphas;                                                                          
 283     private int mLastChildCount = -1;                                                                    
 284     private float mTransitionProgress;                                                                   
 285                                                                                                          
 286     float mOverScrollEffect = 0f;                                                                        
 287                                                                                                          
 288     private Runnable mDeferredAction;                                                                    
 289     private boolean mDeferDropAfterUninstall;                                                            
 290     private boolean mUninstallSuccessful;                                                                
 291                                                                                                          
 292     private final Runnable mBindPages = new Runnable() {                                                 
 293         @Override                                                                                        
 294         public void run() {                                                                              
 295             mLauncher.getModel().bindRemainingSynchronousPages();                                        
 296         }                                                                                                
 297     };                                                                                                   
 298                                                                                                          
 299     /**                                                                                                  
 300      * Used to inflate the Workspace from XML.                                                           
 301      *                                                                                                   
 302      * @param context The application's context.                                                         
 303      * @param attrs The attributes set containing the Workspace's customization values.                  
 304      */                                                                                                  
 305     public Workspace(Context context, AttributeSet attrs) {                                              
 306         this(context, attrs, 0);                                                                         
 307     }                                                                                                    
 308                                                                                                          
 309     /**                                                                                                  
 310      * Used to inflate the Workspace from XML.                                                           
 311      *                                                                                                   
 312      * @param context The application's context.                                                         
 313      * @param attrs The attributes set containing the Workspace's customization values.                  
 314      * @param defStyle Unused.                                                                           
 315      */                                                                                                  
 316     public Workspace(Context context, AttributeSet attrs, int defStyle) {                                
 317         super(context, attrs, defStyle);                                                                 
 318         mContentIsRefreshable = false;                                                                   
 319                                                                                                          
 320         mOutlineHelper = HolographicOutlineHelper.obtain(context);                                       
 321                                                                                                          
 322         mDragEnforcer = new DropTarget.DragEnforcer(context);                                            
 323         // With workspace, data is available straight from the get-go                                    
 324         setDataIsReady();                                                                                
 325                                                                                                          
 326         mLauncher = (Launcher) context;                                                                  
 327         final Resources res = getResources();                                                            
 328         mWorkspaceFadeInAdjacentScreens = LauncherAppState.getInstance().getDynamicGrid().               
 329                 getDeviceProfile().shouldFadeAdjacentWorkspaceScreens();                                 
 330         mFadeInAdjacentScreens = false;                                                                  
 331         mWallpaperManager = WallpaperManager.getInstance(context);                                       
 332                                                                                                          
 333         LauncherAppState app = LauncherAppState.getInstance();                                           
 334         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                    
 335         TypedArray a = context.obtainStyledAttributes(attrs,                                             
 336                 R.styleable.Workspace, defStyle, 0);                                                     
 337         mSpringLoadedShrinkFactor =                                                                      
 338             res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f;               
 339         mOverviewModeShrinkFactor = grid.getOverviewModeScale();                                         
 340         mCameraDistance = res.getInteger(R.integer.config_cameraDistance);                               
 341         mOriginalDefaultPage = mDefaultPage = a.getInt(R.styleable.Workspace_defaultScreen, 1);          
 342         a.recycle();                                                                                     
 343                                                                                                          
 344         setOnHierarchyChangeListener(this);                                                              
 345         setHapticFeedbackEnabled(false);                                                                 
 346                                                                                                          
 347         initWorkspace();                                                                                 
 348                                                                                                          
 349         // Disable multitouch across the workspace/all apps/customize tray                               
 350         setMotionEventSplittingEnabled(true);                                                            
 351         setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);                              
 352     }                                                                                                    
 353                                                                                                          
 354     @Override                                                                                            
 355     public void setInsets(Rect insets) {                                                                 
 356         mInsets.set(insets);                                                                             
 357                                                                                                          
 358         CellLayout customScreen = getScreenWithId(CUSTOM_CONTENT_SCREEN_ID);                             
 359         if (customScreen != null) {                                                                      
 360             View customContent = customScreen.getShortcutsAndWidgets().getChildAt(0);                    
 361             if (customContent instanceof Insettable) {                                                   
 362                 ((Insettable) customContent).setInsets(mInsets);                                         
 363             }                                                                                            
 364         }                                                                                                
 365     }                                                                                                    
 366                                                                                                          
 367     // estimate the size of a widget with spans hSpan, vSpan. return MAX_VALUE for each                  
 368     // dimension if unsuccessful                                                                         
 369     public int[] estimateItemSize(int hSpan, int vSpan,                                                  
 370             ItemInfo itemInfo, boolean springLoaded) {                                                   
 371         int[] size = new int[2];                                                                         
 372         if (getChildCount() > 0) {                                                                       
 373             // Use the first non-custom page to estimate the child position                              
 374             CellLayout cl = (CellLayout) getChildAt(numCustomPages());                                   
 375             Rect r = estimateItemPosition(cl, itemInfo, 0, 0, hSpan, vSpan);                             
 376             size[0] = r.width();                                                                         
 377             size[1] = r.height();                                                                        
 378             if (springLoaded) {                                                                          
 379                 size[0] *= mSpringLoadedShrinkFactor;                                                    
 380                 size[1] *= mSpringLoadedShrinkFactor;                                                    
 381             }                                                                                            
 382             return size;                                                                                 
 383         } else {                                                                                         
 384             size[0] = Integer.MAX_VALUE;                                                                 
 385             size[1] = Integer.MAX_VALUE;                                                                 
 386             return size;                                                                                 
 387         }                                                                                                
 388     }                                                                                                    
 389                                                                                                          
 390     public Rect estimateItemPosition(CellLayout cl, ItemInfo pendingInfo,                                
 391             int hCell, int vCell, int hSpan, int vSpan) {                                                
 392         Rect r = new Rect();                                                                             
 393         cl.cellToRect(hCell, vCell, hSpan, vSpan, r);                                                    
 394         return r;                                                                                        
 395     }                                                                                                    
 396                                                                                                          
 397     public void onDragStart(final DragSource source, Object info, int dragAction) {                      
 398         mIsDragOccuring = true;                                                                          
 399         updateChildrenLayersEnabled(false);                                                              
 400         mLauncher.lockScreenOrientation();                                                               
 401         mLauncher.onInteractionBegin();                                                                  
 402         setChildrenBackgroundAlphaMultipliers(1f);                                                       
 403         // Prevent any Un/InstallShortcutReceivers from updating the db while we are dragging            
 404         InstallShortcutReceiver.enableInstallQueue();                                                    
 405         UninstallShortcutReceiver.enableUninstallQueue();                                                
 406         post(new Runnable() {                                                                            
 407             @Override                                                                                    
 408             public void run() {                                                                          
 409                 if (mIsDragOccuring) {                                                                   
 410                     mDeferRemoveExtraEmptyScreen = false;                                                
 411                     addExtraEmptyScreenOnDrag();                                                         
 412                 }                                                                                        
 413             }                                                                                            
 414         });                                                                                              
 415     }                                                                                                    
 416                                                                                                          
 417                                                                                                          
 418     public void deferRemoveExtraEmptyScreen() {                                                          
 419         mDeferRemoveExtraEmptyScreen = true;                                                             
 420     }                                                                                                    
 421                                                                                                          
 422     public void onDragEnd() {                                                                            
 423         if (!mDeferRemoveExtraEmptyScreen) {                                                             
 424             removeExtraEmptyScreen(true, mDragSourceInternal != null);                                   
 425         }                                                                                                
 426                                                                                                          
 427         mIsDragOccuring = false;                                                                         
 428         updateChildrenLayersEnabled(false);                                                              
 429         mLauncher.unlockScreenOrientation(false);                                                        
 430                                                                                                          
 431         // Re-enable any Un/InstallShortcutReceiver and now process any queued items                     
 432         InstallShortcutReceiver.disableAndFlushInstallQueue(getContext());                               
 433         UninstallShortcutReceiver.disableAndFlushUninstallQueue(getContext());                           
 434                                                                                                          
 435         mDragSourceInternal = null;                                                                      
 436         mLauncher.onInteractionEnd();                                                                    
 437     }                                                                                                    
 438                                                                                                          
 439     /**                                                                                                  
 440      * Initializes various states for this workspace.                                                    
 441      */                                                                                                  
 442     protected void initWorkspace() {                                                                     
 443         mCurrentPage = mDefaultPage;                                                                     
 444         Launcher.setScreen(mCurrentPage);                                                                
 445         LauncherAppState app = LauncherAppState.getInstance();                                           
 446         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                    
 447         mIconCache = app.getIconCache();                                                                 
 448         setWillNotDraw(false);                                                                           
 449         setClipChildren(false);                                                                          
 450         setClipToPadding(false);                                                                         
 451         setChildrenDrawnWithCacheEnabled(true);                                                          
 452                                                                                                          
 453         setMinScale(mOverviewModeShrinkFactor);                                                          
 454         setupLayoutTransition();                                                                         
 455                                                                                                          
 456         mWallpaperOffset = new WallpaperOffsetInterpolator();                                            
 457         Display display = mLauncher.getWindowManager().getDefaultDisplay();                              
 458         display.getSize(mDisplaySize);                                                                   
 459                                                                                                          
 460         mMaxDistanceForFolderCreation = (0.55f * grid.iconSizePx);                                       
 461         mFlingThresholdVelocity = (int) (FLING_THRESHOLD_VELOCITY * mDensity);                           
 462                                                                                                          
 463         // Set the wallpaper dimensions when Launcher starts up                                          
 464         setWallpaperDimension();                                                                         
 465     }                                                                                                    
 466                                                                                                          
 467     private void setupLayoutTransition() {                                                               
 468         // We want to show layout transitions when pages are deleted, to close the gap.                  
 469         mLayoutTransition = new LayoutTransition();                                                      
 470         mLayoutTransition.enableTransitionType(LayoutTransition.DISAPPEARING);                           
 471         mLayoutTransition.enableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);                    
 472         mLayoutTransition.disableTransitionType(LayoutTransition.APPEARING);                             
 473         mLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_APPEARING);                      
 474         setLayoutTransition(mLayoutTransition);                                                          
 475     }                                                                                                    
 476                                                                                                          
 477     void enableLayoutTransitions() {                                                                     
 478         setLayoutTransition(mLayoutTransition);                                                          
 479     }                                                                                                    
 480     void disableLayoutTransitions() {                                                                    
 481         setLayoutTransition(null);                                                                       
 482     }                                                                                                    
 483                                                                                                          
 484     @Override                                                                                            
 485     protected int getScrollMode() {                                                                      
 486         return SmoothPagedView.X_LARGE_MODE;                                                             
 487     }                                                                                                    
 488                                                                                                          
 489     @Override                                                                                            
 490     public void onChildViewAdded(View parent, View child) {                                              
 491         if (!(child instanceof CellLayout)) {                                                            
 492             throw new IllegalArgumentException("A Workspace can only have CellLayout children.");        
 493         }                                                                                                
 494         CellLayout cl = ((CellLayout) child);                                                            
 495         cl.setOnInterceptTouchListener(this);                                                            
 496         cl.setClickable(true);                                                                           
 497         cl.setImportantForAccessibility(ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO);                      
 498         super.onChildViewAdded(parent, child);                                                           
 499     }                                                                                                    
 500                                                                                                          
 501     protected boolean shouldDrawChild(View child) {                                                      
 502         final CellLayout cl = (CellLayout) child;                                                        
 503         return super.shouldDrawChild(child) &&                                                           
 504             (mIsSwitchingState ||                                                                        
 505              cl.getShortcutsAndWidgets().getAlpha() > 0 ||                                               
 506              cl.getBackgroundAlpha() > 0);                                                               
 507     }                                                                                                    
 508                                                                                                          
 509     /**                                                                                                  
 510      * @return The open folder on the current screen, or null if there is none                           
 511      */                                                                                                  
 512     Folder getOpenFolder() {                                                                             
 513         DragLayer dragLayer = mLauncher.getDragLayer();                                                  
 514         int count = dragLayer.getChildCount();                                                           
 515         for (int i = 0; i < count; i++) {                                                                
 516             View child = dragLayer.getChildAt(i);                                                        
 517             if (child instanceof Folder) {                                                               
 518                 Folder folder = (Folder) child;                                                          
 519                 if (folder.getInfo().opened)                                                             
 520                     return folder;                                                                       
 521             }                                                                                            
 522         }                                                                                                
 523         return null;                                                                                     
 524     }                                                                                                    
 525                                                                                                          
 526     boolean isTouchActive() {                                                                            
 527         return mTouchState != TOUCH_STATE_REST;                                                          
 528     }                                                                                                    
 529                                                                                                          
 530     public void removeAllWorkspaceScreens() {                                                            
 531         // Disable all layout transitions before removing all pages to ensure that we don't get the      
 532         // transition animations competing with us changing the scroll when we add pages or the          
 533         // custom content screen                                                                         
 534         disableLayoutTransitions();                                                                      
 535                                                                                                          
 536         // Since we increment the current page when we call addCustomContentPage via bindScreens         
 537         // (and other places), we need to adjust the current page back when we clear the pages           
 538         if (hasCustomContent()) {                                                                        
 539             removeCustomContentPage();                                                                   
 540         }                                                                                                
 541                                                                                                          
 542         // Remove the pages and clear the screen models                                                  
 543         removeAllViews();                                                                                
 544         mScreenOrder.clear();                                                                            
 545         mWorkspaceScreens.clear();                                                                       
 546                                                                                                          
 547         // Re-enable the layout transitions                                                              
 548         enableLayoutTransitions();                                                                       
 549     }                                                                                                    
 550                                                                                                          
 551     public long insertNewWorkspaceScreenBeforeEmptyScreen(long screenId) {                               
 552         // Find the index to insert this view into.  If the empty screen exists, then                    
 553         // insert it before that.                                                                        
 554         int insertIndex = mScreenOrder.indexOf(EXTRA_EMPTY_SCREEN_ID);                                   
 555         if (insertIndex < 0) {                                                                           
 556             insertIndex = mScreenOrder.size();                                                           
 557         }                                                                                                
 558         return insertNewWorkspaceScreen(screenId, insertIndex);                                          
 559     }                                                                                                    
 560                                                                                                          
 561     public long insertNewWorkspaceScreen(long screenId) {                                                
 562         return insertNewWorkspaceScreen(screenId, getChildCount());                                      
 563     }                                                                                                    
 564                                                                                                          
 565     public long insertNewWorkspaceScreen(long screenId, int insertIndex) {                               
 566         // Log to disk                                                                                   
 567         Launcher.addDumpLog(TAG, "11683562 - insertNewWorkspaceScreen(): " + screenId +                  
 568                 " at index: " + insertIndex, true);                                                      
 569                                                                                                          
 570         if (mWorkspaceScreens.containsKey(screenId)) {                                                   
 571             throw new RuntimeException("Screen id " + screenId + " already exists!");                    
 572         }                                                                                                
 573                                                                                                          
 574         CellLayout newScreen = (CellLayout)                                                              
 575                 mLauncher.getLayoutInflater().inflate(R.layout.workspace_screen, null);                  
 576                                                                                                          
 577         newScreen.setOnLongClickListener(mLongClickListener);                                            
 578         newScreen.setOnClickListener(mLauncher);                                                         
 579         newScreen.setSoundEffectsEnabled(false);                                                         
 580         mWorkspaceScreens.put(screenId, newScreen);                                                      
 581         mScreenOrder.add(insertIndex, screenId);                                                         
 582         addView(newScreen, insertIndex);                                                                 
 583         return screenId;                                                                                 
 584     }                                                                                                    
 585                                                                                                          
 586     public void createCustomContentContainer() {                                                         
 587         CellLayout customScreen = (CellLayout)                                                           
 588                 mLauncher.getLayoutInflater().inflate(R.layout.workspace_screen, null);                  
 589         customScreen.disableBackground();                                                                
 590         customScreen.disableDragTarget();                                                                
 591                                                                                                          
 592         mWorkspaceScreens.put(CUSTOM_CONTENT_SCREEN_ID, customScreen);                                   
 593         mScreenOrder.add(0, CUSTOM_CONTENT_SCREEN_ID);                                                   
 594                                                                                                          
 595         // We want no padding on the custom content                                                      
 596         customScreen.setPadding(0, 0, 0, 0);                                                             
 597                                                                                                          
 598         addFullScreenPage(customScreen);                                                                 
 599                                                                                                          
 600         // Ensure that the current page and default page are maintained.                                 
 601         mDefaultPage = mOriginalDefaultPage + 1;                                                         
 602                                                                                                          
 603         // Update the custom content hint                                                                
 604         if (mRestorePage != INVALID_RESTORE_PAGE) {                                                      
 605             mRestorePage = mRestorePage + 1;                                                             
 606         } else {                                                                                         
 607             setCurrentPage(getCurrentPage() + 1);                                                        
 608         }                                                                                                
 609     }                                                                                                    
 610                                                                                                          
 611     public void removeCustomContentPage() {                                                              
 612         CellLayout customScreen = getScreenWithId(CUSTOM_CONTENT_SCREEN_ID);                             
 613         if (customScreen == null) {                                                                      
 614             throw new RuntimeException("Expected custom content screen to exist");                       
 615         }                                                                                                
 616                                                                                                          
 617         mWorkspaceScreens.remove(CUSTOM_CONTENT_SCREEN_ID);                                              
 618         mScreenOrder.remove(CUSTOM_CONTENT_SCREEN_ID);                                                   
 619         removeView(customScreen);                                                                        
 620                                                                                                          
 621         if (mCustomContentCallbacks != null) {                                                           
 622             mCustomContentCallbacks.onScrollProgressChanged(0);                                          
 623             mCustomContentCallbacks.onHide();                                                            
 624         }                                                                                                
 625                                                                                                          
 626         mCustomContentCallbacks = null;                                                                  
 627                                                                                                          
 628         // Ensure that the current page and default page are maintained.                                 
 629         mDefaultPage = mOriginalDefaultPage - 1;                                                         
 630                                                                                                          
 631         // Update the custom content hint                                                                
 632         if (mRestorePage != INVALID_RESTORE_PAGE) {                                                      
 633             mRestorePage = mRestorePage - 1;                                                             
 634         } else {                                                                                         
 635             setCurrentPage(getCurrentPage() - 1);                                                        
 636         }                                                                                                
 637     }                                                                                                    
 638                                                                                                          
 639     public void addToCustomContentPage(View customContent, CustomContentCallbacks callbacks,             
 640             String description) {                                                                        
 641         if (getPageIndexForScreenId(CUSTOM_CONTENT_SCREEN_ID) < 0) {                                     
 642             throw new RuntimeException("Expected custom content screen to exist");                       
 643         }                                                                                                
 644                                                                                                          
 645         // Add the custom content to the full screen custom page                                         
 646         CellLayout customScreen = getScreenWithId(CUSTOM_CONTENT_SCREEN_ID);                             
 647         int spanX = customScreen.getCountX();                                                            
 648         int spanY = customScreen.getCountY();                                                            
 649         CellLayout.LayoutParams lp = new CellLayout.LayoutParams(0, 0, spanX, spanY);                    
 650         lp.canReorder  = false;                                                                          
 651         lp.isFullscreen = true;                                                                          
 652         if (customContent instanceof Insettable) {                                                       
 653             ((Insettable)customContent).setInsets(mInsets);                                              
 654         }                                                                                                
 655                                                                                                          
 656         // Verify that the child is removed from any existing parent.                                    
 657         if (customContent.getParent() instanceof ViewGroup) {                                            
 658             ViewGroup parent = (ViewGroup) customContent.getParent();                                    
 659             parent.removeView(customContent);                                                            
 660         }                                                                                                
 661         customScreen.removeAllViews();                                                                   
 662         customScreen.addViewToCellLayout(customContent, 0, 0, lp, true);                                 
 663         mCustomContentDescription = description;                                                         
 664                                                                                                          
 665         mCustomContentCallbacks = callbacks;                                                             
 666     }                                                                                                    
 667                                                                                                          
 668     public void addExtraEmptyScreenOnDrag() {                                                            
 669         // Log to disk                                                                                   
 670         Launcher.addDumpLog(TAG, "11683562 - addExtraEmptyScreenOnDrag()", true);                        
 671                                                                                                          
 672         boolean lastChildOnScreen = false;                                                               
 673         boolean childOnFinalScreen = false;                                                              
 674                                                                                                          
 675         // Cancel any pending removal of empty screen                                                    
 676         mRemoveEmptyScreenRunnable = null;                                                               
 677                                                                                                          
 678         if (mDragSourceInternal != null) {                                                               
 679             if (mDragSourceInternal.getChildCount() == 1) {                                              
 680                 lastChildOnScreen = true;                                                                
 681             }                                                                                            
 682             CellLayout cl = (CellLayout) mDragSourceInternal.getParent();                                
 683             if (indexOfChild(cl) == getChildCount() - 1) {                                               
 684                 childOnFinalScreen = true;                                                               
 685             }                                                                                            
 686         }                                                                                                
 687                                                                                                          
 688         // If this is the last item on the final screen                                                  
 689         if (lastChildOnScreen && childOnFinalScreen) {                                                   
 690             return;                                                                                      
 691         }                                                                                                
 692         if (!mWorkspaceScreens.containsKey(EXTRA_EMPTY_SCREEN_ID)) {                                     
 693             insertNewWorkspaceScreen(EXTRA_EMPTY_SCREEN_ID);                                             
 694         }                                                                                                
 695     }                                                                                                    
 696                                                                                                          
 697     public boolean addExtraEmptyScreen() {                                                               
 698         // Log to disk                                                                                   
 699         Launcher.addDumpLog(TAG, "11683562 - addExtraEmptyScreen()", true);                              
 700                                                                                                          
 701         if (!mWorkspaceScreens.containsKey(EXTRA_EMPTY_SCREEN_ID)) {                                     
 702             insertNewWorkspaceScreen(EXTRA_EMPTY_SCREEN_ID);                                             
 703             return true;                                                                                 
 704         }                                                                                                
 705         return false;                                                                                    
 706     }                                                                                                    
 707                                                                                                          
 708     private void convertFinalScreenToEmptyScreenIfNecessary() {                                          
 709         // Log to disk                                                                                   
 710         Launcher.addDumpLog(TAG, "11683562 - convertFinalScreenToEmptyScreenIfNecessary()", true);       
 711                                                                                                          
 712         if (mLauncher.isWorkspaceLoading()) {                                                            
 713             // Invalid and dangerous operation if workspace is loading                                   
 714             Launcher.addDumpLog(TAG, "    - workspace loading, skip", true);                             
 715             return;                                                                                      
 716         }                                                                                                
 717                                                                                                          
 718         if (hasExtraEmptyScreen() || mScreenOrder.size() == 0) return;                                   
 719         long finalScreenId = mScreenOrder.get(mScreenOrder.size() - 1);                                  
 720                                                                                                          
 721         if (finalScreenId == CUSTOM_CONTENT_SCREEN_ID) return;                                           
 722         CellLayout finalScreen = mWorkspaceScreens.get(finalScreenId);                                   
 723                                                                                                          
 724         // If the final screen is empty, convert it to the extra empty screen                            
 725         if (finalScreen.getShortcutsAndWidgets().getChildCount() == 0 &&                                 
 726                 !finalScreen.isDropPending()) {                                                          
 727             mWorkspaceScreens.remove(finalScreenId);                                                     
 728             mScreenOrder.remove(finalScreenId);                                                          
 729                                                                                                          
 730             // if this is the last non-custom content screen, convert it to the empty screen             
 731             mWorkspaceScreens.put(EXTRA_EMPTY_SCREEN_ID, finalScreen);                                   
 732             mScreenOrder.add(EXTRA_EMPTY_SCREEN_ID);                                                     
 733                                                                                                          
 734             // Update the model if we have changed any screens                                           
 735             mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder);                    
 736             Launcher.addDumpLog(TAG, "11683562 -   extra empty screen: " + finalScreenId, true);         
 737         }                                                                                                
 738     }                                                                                                    
 739                                                                                                          
 740     public void removeExtraEmptyScreen(final boolean animate, boolean stripEmptyScreens) {               
 741         removeExtraEmptyScreenDelayed(animate, null, 0, stripEmptyScreens);                              
 742     }                                                                                                    
 743                                                                                                          
 744     public void removeExtraEmptyScreenDelayed(final boolean animate, final Runnable onComplete,          
 745             final int delay, final boolean stripEmptyScreens) {                                          
 746         // Log to disk                                                                                   
 747         Launcher.addDumpLog(TAG, "11683562 - removeExtraEmptyScreen()", true);                           
 748         if (mLauncher.isWorkspaceLoading()) {                                                            
 749             // Don't strip empty screens if the workspace is still loading                               
 750             Launcher.addDumpLog(TAG, "    - workspace loading, skip", true);                             
 751             return;                                                                                      
 752         }                                                                                                
 753                                                                                                          
 754         if (delay > 0) {                                                                                 
 755             postDelayed(new Runnable() {                                                                 
 756                 @Override                                                                                
 757                 public void run() {                                                                      
 758                     removeExtraEmptyScreenDelayed(animate, onComplete, 0, stripEmptyScreens);            
 759                 }                                                                                        
 760             }, delay);                                                                                   
 761             return;                                                                                      
 762         }                                                                                                
 763                                                                                                          
 764         convertFinalScreenToEmptyScreenIfNecessary();                                                    
 765         if (hasExtraEmptyScreen()) {                                                                     
 766             int emptyIndex = mScreenOrder.indexOf(EXTRA_EMPTY_SCREEN_ID);                                
 767             if (getNextPage() == emptyIndex) {                                                           
 768                 snapToPage(getNextPage() - 1, SNAP_OFF_EMPTY_SCREEN_DURATION);                           
 769                 fadeAndRemoveEmptyScreen(SNAP_OFF_EMPTY_SCREEN_DURATION, FADE_EMPTY_SCREEN_DURATION,     
 770                         onComplete, stripEmptyScreens);                                                  
 771             } else {                                                                                     
 772                 fadeAndRemoveEmptyScreen(0, FADE_EMPTY_SCREEN_DURATION,                                  
 773                         onComplete, stripEmptyScreens);                                                  
 774             }                                                                                            
 775             return;                                                                                      
 776         } else if (stripEmptyScreens) {                                                                  
 777             // If we're not going to strip the empty screens after removing                              
 778             // the extra empty screen, do it right away.                                                 
 779             stripEmptyScreens();                                                                         
 780         }                                                                                                
 781                                                                                                          
 782         if (onComplete != null) {                                                                        
 783             onComplete.run();                                                                            
 784         }                                                                                                
 785     }                                                                                                    
 786                                                                                                          
 787     private void fadeAndRemoveEmptyScreen(int delay, int duration, final Runnable onComplete,            
 788             final boolean stripEmptyScreens) {                                                           
 789         // Log to disk                                                                                   
 790         // XXX: Do we need to update LM workspace screens below?                                         
 791         Launcher.addDumpLog(TAG, "11683562 - fadeAndRemoveEmptyScreen()", true);                         
 792         PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 0f);                          
 793         PropertyValuesHolder bgAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha", 0f);              
 794                                                                                                          
 795         final CellLayout cl = mWorkspaceScreens.get(EXTRA_EMPTY_SCREEN_ID);                              
 796                                                                                                          
 797         mRemoveEmptyScreenRunnable = new Runnable() {                                                    
 798             @Override                                                                                    
 799             public void run() {                                                                          
 800                 if (hasExtraEmptyScreen()) {                                                             
 801                     mWorkspaceScreens.remove(EXTRA_EMPTY_SCREEN_ID);                                     
 802                     mScreenOrder.remove(EXTRA_EMPTY_SCREEN_ID);                                          
 803                     removeView(cl);                                                                      
 804                     if (stripEmptyScreens) {                                                             
 805                         stripEmptyScreens();                                                             
 806                     }                                                                                    
 807                 }                                                                                        
 808             }                                                                                            
 809         };                                                                                               
 810                                                                                                          
 811         ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(cl, alpha, bgAlpha);                   
 812         oa.setDuration(duration);                                                                        
 813         oa.setStartDelay(delay);                                                                         
 814         oa.addListener(new AnimatorListenerAdapter() {                                                   
 815             @Override                                                                                    
 816             public void onAnimationEnd(Animator animation) {                                             
 817                 if (mRemoveEmptyScreenRunnable != null) {                                                
 818                     mRemoveEmptyScreenRunnable.run();                                                    
 819                 }                                                                                        
 820                 if (onComplete != null) {                                                                
 821                     onComplete.run();                                                                    
 822                 }                                                                                        
 823             }                                                                                            
 824         });                                                                                              
 825         oa.start();                                                                                      
 826     }                                                                                                    
 827                                                                                                          
 828     public boolean hasExtraEmptyScreen() {                                                               
 829         int nScreens = getChildCount();                                                                  
 830         nScreens = nScreens - numCustomPages();                                                          
 831         return mWorkspaceScreens.containsKey(EXTRA_EMPTY_SCREEN_ID) && nScreens > 1;                     
 832     }                                                                                                    
 833                                                                                                          
 834     public long commitExtraEmptyScreen() {                                                               
 835         // Log to disk                                                                                   
 836         Launcher.addDumpLog(TAG, "11683562 - commitExtraEmptyScreen()", true);                           
 837         if (mLauncher.isWorkspaceLoading()) {                                                            
 838             // Invalid and dangerous operation if workspace is loading                                   
 839             Launcher.addDumpLog(TAG, "    - workspace loading, skip", true);                             
 840             return -1;                                                                                   
 841         }                                                                                                
 842                                                                                                          
 843         int index = getPageIndexForScreenId(EXTRA_EMPTY_SCREEN_ID);                                      
 844         CellLayout cl = mWorkspaceScreens.get(EXTRA_EMPTY_SCREEN_ID);                                    
 845         mWorkspaceScreens.remove(EXTRA_EMPTY_SCREEN_ID);                                                 
 846         mScreenOrder.remove(EXTRA_EMPTY_SCREEN_ID);                                                      
 847                                                                                                          
 848         long newId = LauncherAppState.getLauncherProvider().generateNewScreenId();                       
 849         mWorkspaceScreens.put(newId, cl);                                                                
 850         mScreenOrder.add(newId);                                                                         
 851                                                                                                          
 852         // Update the page indicator marker                                                              
 853         if (getPageIndicator() != null) {                                                                
 854             getPageIndicator().updateMarker(index, getPageIndicatorMarker(index));                       
 855         }                                                                                                
 856                                                                                                          
 857         // Update the model for the new screen                                                           
 858         mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder);                        
 859                                                                                                          
 860         return newId;                                                                                    
 861     }                                                                                                    
 862                                                                                                          
 863     public CellLayout getScreenWithId(long screenId) {                                                   
 864         CellLayout layout = mWorkspaceScreens.get(screenId);                                             
 865         return layout;                                                                                   
 866     }                                                                                                    
 867                                                                                                          
 868     public long getIdForScreen(CellLayout layout) {                                                      
 869         Iterator<Long> iter = mWorkspaceScreens.keySet().iterator();                                     
 870         while (iter.hasNext()) {                                                                         
 871             long id = iter.next();                                                                       
 872             if (mWorkspaceScreens.get(id) == layout) {                                                   
 873                 return id;                                                                               
 874             }                                                                                            
 875         }                                                                                                
 876         return -1;                                                                                       
 877     }                                                                                                    
 878                                                                                                          
 879     public int getPageIndexForScreenId(long screenId) {                                                  
 880         return indexOfChild(mWorkspaceScreens.get(screenId));                                            
 881     }                                                                                                    
 882                                                                                                          
 883     public long getScreenIdForPageIndex(int index) {                                                     
 884         if (0 <= index && index < mScreenOrder.size()) {                                                 
 885             return mScreenOrder.get(index);                                                              
 886         }                                                                                                
 887         return -1;                                                                                       
 888     }                                                                                                    
 889                                                                                                          
 890     ArrayList<Long> getScreenOrder() {                                                                   
 891         return mScreenOrder;                                                                             
 892     }                                                                                                    
 893                                                                                                          
 894     public void stripEmptyScreens() {                                                                    
 895         // Log to disk                                                                                   
 896         Launcher.addDumpLog(TAG, "11683562 - stripEmptyScreens()", true);                                
 897                                                                                                          
 898         if (mLauncher.isWorkspaceLoading()) {                                                            
 899             // Don't strip empty screens if the workspace is still loading.                              
 900             // This is dangerous and can result in data loss.                                            
 901             Launcher.addDumpLog(TAG, "    - workspace loading, skip", true);                             
 902             return;                                                                                      
 903         }                                                                                                
 904                                                                                                          
 905         if (isPageMoving()) {                                                                            
 906             mStripScreensOnPageStopMoving = true;                                                        
 907             return;                                                                                      
 908         }                                                                                                
 909                                                                                                          
 910         int currentPage = getNextPage();                                                                 
 911         ArrayList<Long> removeScreens = new ArrayList<Long>();                                           
 912         for (Long id: mWorkspaceScreens.keySet()) {                                                      
 913             CellLayout cl = mWorkspaceScreens.get(id);                                                   
 914             if (id >= 0 && cl.getShortcutsAndWidgets().getChildCount() == 0) {                           
 915                 removeScreens.add(id);                                                                   
 916             }                                                                                            
 917         }                                                                                                
 918                                                                                                          
 919         // We enforce at least one page to add new items to. In the case that we remove the last         
 920         // such screen, we convert the last screen to the empty screen                                   
 921         int minScreens = 1 + numCustomPages();                                                           
 922                                                                                                          
 923         int pageShift = 0;                                                                               
 924         for (Long id: removeScreens) {                                                                   
 925             Launcher.addDumpLog(TAG, "11683562 -   removing id: " + id, true);                           
 926             CellLayout cl = mWorkspaceScreens.get(id);                                                   
 927             mWorkspaceScreens.remove(id);                                                                
 928             mScreenOrder.remove(id);                                                                     
 929                                                                                                          
 930             if (getChildCount() > minScreens) {                                                          
 931                 if (indexOfChild(cl) < currentPage) {                                                    
 932                     pageShift++;                                                                         
 933                 }                                                                                        
 934                 removeView(cl);                                                                          
 935             } else {                                                                                     
 936                 // if this is the last non-custom content screen, convert it to the empty screen         
 937                 mRemoveEmptyScreenRunnable = null;                                                       
 938                 mWorkspaceScreens.put(EXTRA_EMPTY_SCREEN_ID, cl);                                        
 939                 mScreenOrder.add(EXTRA_EMPTY_SCREEN_ID);                                                 
 940             }                                                                                            
 941         }                                                                                                
 942                                                                                                          
 943         if (!removeScreens.isEmpty()) {                                                                  
 944             // Update the model if we have changed any screens                                           
 945             mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder);                    
 946         }                                                                                                
 947                                                                                                          
 948         if (pageShift >= 0) {                                                                            
 949             setCurrentPage(currentPage - pageShift);                                                     
 950         }                                                                                                
 951     }                                                                                                    
 952                                                                                                          
 953     // See implementation for parameter definition.                                                      
 954     void addInScreen(View child, long container, long screenId,                                          
 955             int x, int y, int spanX, int spanY) {                                                        
 956         addInScreen(child, container, screenId, x, y, spanX, spanY, false, false);                       
 957     }                                                                                                    
 958                                                                                                          
 959     // At bind time, we use the rank (screenId) to compute x and y for hotseat items.                    
 960     // See implementation for parameter definition.                                                      
 961     void addInScreenFromBind(View child, long container, long screenId, int x, int y,                    
 962             int spanX, int spanY) {                                                                      
 963         addInScreen(child, container, screenId, x, y, spanX, spanY, false, true);                        
 964     }                                                                                                    
 965                                                                                                          
 966     // See implementation for parameter definition.                                                      
 967     void addInScreen(View child, long container, long screenId, int x, int y, int spanX, int spanY,      
 968             boolean insert) {                                                                            
 969         addInScreen(child, container, screenId, x, y, spanX, spanY, insert, false);                      
 970     }                                                                                                    
 971                                                                                                          
 972     /**                                                                                                  
 973      * Adds the specified child in the specified screen. The position and dimension of                   
 974      * the child are defined by x, y, spanX and spanY.                                                   
 975      *                                                                                                   
 976      * @param child The child to add in one of the workspace's screens.                                  
 977      * @param screenId The screen in which to add the child.                                             
 978      * @param x The X position of the child in the screen's grid.                                        
 979      * @param y The Y position of the child in the screen's grid.                                        
 980      * @param spanX The number of cells spanned horizontally by the child.                               
 981      * @param spanY The number of cells spanned vertically by the child.                                 
 982      * @param insert When true, the child is inserted at the beginning of the children list.             
 983      * @param computeXYFromRank When true, we use the rank (stored in screenId) to compute               
 984      *                          the x and y position in which to place hotseat items. Otherwise          
 985      *                          we use the x and y position to compute the rank.                         
 986      */                                                                                                  
 987     void addInScreen(View child, long container, long screenId, int x, int y, int spanX, int spanY,      
 988             boolean insert, boolean computeXYFromRank) {                                                 
 989         if (container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {                                 
 990             if (getScreenWithId(screenId) == null) {                                                     
 991                 Log.e(TAG, "Skipping child, screenId " + screenId + " not found");                       
 992                 // DEBUGGING - Print out the stack trace to see where we are adding from                 
 993                 new Throwable().printStackTrace();                                                       
 994                 return;                                                                                  
 995             }                                                                                            
 996         }                                                                                                
 997         if (screenId == EXTRA_EMPTY_SCREEN_ID) {                                                         
 998             // This should never happen                                                                  
 999             throw new RuntimeException("Screen id should not be EXTRA_EMPTY_SCREEN_ID");                 
1000         }                                                                                                
1001                                                                                                          
1002         final CellLayout layout;                                                                         
1003         if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                 
1004             layout = mLauncher.getHotseat().getLayout();                                                 
1005             child.setOnKeyListener(new HotseatIconKeyEventListener());                                   
1006                                                                                                          
1007             // Hide folder title in the hotseat                                                          
1008             if (child instanceof FolderIcon) {                                                           
1009                 ((FolderIcon) child).setTextVisible(false);                                              
1010             }                                                                                            
1011                                                                                                          
1012             if (computeXYFromRank) {                                                                     
1013                 x = mLauncher.getHotseat().getCellXFromOrder((int) screenId);                            
1014                 y = mLauncher.getHotseat().getCellYFromOrder((int) screenId);                            
1015             } else {                                                                                     
1016                 screenId = mLauncher.getHotseat().getOrderInHotseat(x, y);                               
1017             }                                                                                            
1018         } else {                                                                                         
1019             // Show folder title if not in the hotseat                                                   
1020             if (child instanceof FolderIcon) {                                                           
1021                 ((FolderIcon) child).setTextVisible(true);                                               
1022             }                                                                                            
1023             layout = getScreenWithId(screenId);                                                          
1024             child.setOnKeyListener(new IconKeyEventListener());                                          
1025         }                                                                                                
1026                                                                                                          
1027         ViewGroup.LayoutParams genericLp = child.getLayoutParams();                                      
1028         CellLayout.LayoutParams lp;                                                                      
1029         if (genericLp == null || !(genericLp instanceof CellLayout.LayoutParams)) {                      
1030             lp = new CellLayout.LayoutParams(x, y, spanX, spanY);                                        
1031         } else {                                                                                         
1032             lp = (CellLayout.LayoutParams) genericLp;                                                    
1033             lp.cellX = x;                                                                                
1034             lp.cellY = y;                                                                                
1035             lp.cellHSpan = spanX;                                                                        
1036             lp.cellVSpan = spanY;                                                                        
1037         }                                                                                                
1038                                                                                                          
1039         if (spanX < 0 && spanY < 0) {                                                                    
1040             lp.isLockedToGrid = false;                                                                   
1041         }                                                                                                
1042                                                                                                          
1043         // Get the canonical child id to uniquely represent this view in this screen                     
1044         ItemInfo info = (ItemInfo) child.getTag();                                                       
1045         int childId = mLauncher.getViewIdForItem(info);                                                  
1046                                                                                                          
1047         boolean markCellsAsOccupied = !(child instanceof Folder);                                        
1048         if (!layout.addViewToCellLayout(child, insert ? 0 : -1, childId, lp, markCellsAsOccupied)) {     
1049             // TODO: This branch occurs when the workspace is adding views                               
1050             // outside of the defined grid                                                               
1051             // maybe we should be deleting these items from the LauncherModel?                           
1052             Launcher.addDumpLog(TAG, "Failed to add to item at (" + lp.cellX + "," + lp.cellY + ") to Cel🔵
1053         }                                                                                                
1054                                                                                                          
1055         if (!(child instanceof Folder)) {                                                                
1056             child.setHapticFeedbackEnabled(false);                                                       
1057             child.setOnLongClickListener(mLongClickListener);                                            
1058         }                                                                                                
1059         if (child instanceof DropTarget) {                                                               
1060             mDragController.addDropTarget((DropTarget) child);                                           
1061         }                                                                                                
1062     }                                                                                                    
1063                                                                                                          
1064     /**                                                                                                  
1065      * Called directly from a CellLayout (not by the framework), after we've been added as a             
1066      * listener via setOnInterceptTouchEventListener(). This allows us to tell the CellLayout            
1067      * that it should intercept touch events, which is not something that is normally supported.         
1068      */                                                                                                  
1069     @Override                                                                                            
1070     public boolean onTouch(View v, MotionEvent event) {                                                  
1071         return (workspaceInModalState() || !isFinishedSwitchingState())                                  
1072                 || (!workspaceInModalState() && indexOfChild(v) != mCurrentPage);                        
1073     }                                                                                                    
1074                                                                                                          
1075     public boolean isSwitchingState() {                                                                  
1076         return mIsSwitchingState;                                                                        
1077     }                                                                                                    
1078                                                                                                          
1079     /** This differs from isSwitchingState in that we take into account how far the transition           
1080      *  has completed. */                                                                                
1081     public boolean isFinishedSwitchingState() {                                                          
1082         return !mIsSwitchingState || (mTransitionProgress > 0.5f);                                       
1083     }                                                                                                    
1084                                                                                                          
1085     protected void onWindowVisibilityChanged (int visibility) {                                          
1086         mLauncher.onWindowVisibilityChanged(visibility);                                                 
1087     }                                                                                                    
1088                                                                                                          
1089     @Override                                                                                            
1090     public boolean dispatchUnhandledMove(View focused, int direction) {                                  
1091         if (workspaceInModalState() || !isFinishedSwitchingState()) {                                    
1092             // when the home screens are shrunken, shouldn't allow side-scrolling                        
1093             return false;                                                                                
1094         }                                                                                                
1095         return super.dispatchUnhandledMove(focused, direction);                                          
1096     }                                                                                                    
1097                                                                                                          
1098     @Override                                                                                            
1099     public boolean onInterceptTouchEvent(MotionEvent ev) {                                               
1100         switch (ev.getAction() & MotionEvent.ACTION_MASK) {                                              
1101         case MotionEvent.ACTION_DOWN:                                                                    
1102             mXDown = ev.getX();                                                                          
1103             mYDown = ev.getY();                                                                          
1104             mTouchDownTime = System.currentTimeMillis();                                                 
1105             break;                                                                                       
1106         case MotionEvent.ACTION_POINTER_UP:                                                              
1107         case MotionEvent.ACTION_UP:                                                                      
1108             if (mTouchState == TOUCH_STATE_REST) {                                                       
1109                 final CellLayout currentPage = (CellLayout) getChildAt(mCurrentPage);                    
1110                 if (currentPage != null && !currentPage.lastDownOnOccupiedCell()) {                      
1111                     onWallpaperTap(ev);                                                                  
1112                 }                                                                                        
1113             }                                                                                            
1114         }                                                                                                
1115         return super.onInterceptTouchEvent(ev);                                                          
1116     }                                                                                                    
1117                                                                                                          
1118     @Override                                                                                            
1119     public boolean onGenericMotionEvent(MotionEvent event) {                                             
1120         // Ignore pointer scroll events if the custom content doesn't allow scrolling.                   
1121         if ((getScreenIdForPageIndex(getCurrentPage()) == CUSTOM_CONTENT_SCREEN_ID)                      
1122                 && (mCustomContentCallbacks != null)                                                     
1123                 && !mCustomContentCallbacks.isScrollingAllowed()) {                                      
1124             return false;                                                                                
1125         }                                                                                                
1126         return super.onGenericMotionEvent(event);                                                        
1127     }                                                                                                    
1128                                                                                                          
1129     protected void reinflateWidgetsIfNecessary() {                                                       
1130         final int clCount = getChildCount();                                                             
1131         for (int i = 0; i < clCount; i++) {                                                              
1132             CellLayout cl = (CellLayout) getChildAt(i);                                                  
1133             ShortcutAndWidgetContainer swc = cl.getShortcutsAndWidgets();                                
1134             final int itemCount = swc.getChildCount();                                                   
1135             for (int j = 0; j < itemCount; j++) {                                                        
1136                 View v = swc.getChildAt(j);                                                              
1137                                                                                                          
1138                 if (v != null  && v.getTag() instanceof LauncherAppWidgetInfo) {                         
1139                     LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) v.getTag();                     
1140                     LauncherAppWidgetHostView lahv = (LauncherAppWidgetHostView) info.hostView;          
1141                     if (lahv != null && lahv.isReinflateRequired()) {                                    
1142                         mLauncher.removeAppWidget(info);                                                 
1143                         // Remove the current widget which is inflated with the wrong orientation        
1144                         cl.removeView(lahv);                                                             
1145                         mLauncher.bindAppWidget(info);                                                   
1146                     }                                                                                    
1147                 }                                                                                        
1148             }                                                                                            
1149         }                                                                                                
1150     }                                                                                                    
1151                                                                                                          
1152     @Override                                                                                            
1153     protected void determineScrollingStart(MotionEvent ev) {                                             
1154         if (!isFinishedSwitchingState()) return;                                                         
1155                                                                                                          
1156         float deltaX = ev.getX() - mXDown;                                                               
1157         float absDeltaX = Math.abs(deltaX);                                                              
1158         float absDeltaY = Math.abs(ev.getY() - mYDown);                                                  
1159                                                                                                          
1160         if (Float.compare(absDeltaX, 0f) == 0) return;                                                   
1161                                                                                                          
1162         float slope = absDeltaY / absDeltaX;                                                             
1163         float theta = (float) Math.atan(slope);                                                          
1164                                                                                                          
1165         if (absDeltaX > mTouchSlop || absDeltaY > mTouchSlop) {                                          
1166             cancelCurrentPageLongPress();                                                                
1167         }                                                                                                
1168                                                                                                          
1169         boolean passRightSwipesToCustomContent =                                                         
1170                 (mTouchDownTime - mCustomContentShowTime) > CUSTOM_CONTENT_GESTURE_DELAY;                
1171                                                                                                          
1172         boolean swipeInIgnoreDirection = isLayoutRtl() ? deltaX < 0 : deltaX > 0;                        
1173         boolean onCustomContentScreen =                                                                  
1174                 getScreenIdForPageIndex(getCurrentPage()) == CUSTOM_CONTENT_SCREEN_ID;                   
1175         if (swipeInIgnoreDirection && onCustomContentScreen && passRightSwipesToCustomContent) {         
1176             // Pass swipes to the right to the custom content page.                                      
1177             return;                                                                                      
1178         }                                                                                                
1179                                                                                                          
1180         if (onCustomContentScreen && (mCustomContentCallbacks != null)                                   
1181                 && !mCustomContentCallbacks.isScrollingAllowed()) {                                      
1182             // Don't allow workspace scrolling if the current custom content screen doesn't allow        
1183             // scrolling.                                                                                
1184             return;                                                                                      
1185         }                                                                                                
1186                                                                                                          
1187         if (theta > MAX_SWIPE_ANGLE) {                                                                   
1188             // Above MAX_SWIPE_ANGLE, we don't want to ever start scrolling the workspace                
1189             return;                                                                                      
1190         } else if (theta > START_DAMPING_TOUCH_SLOP_ANGLE) {                                             
1191             // Above START_DAMPING_TOUCH_SLOP_ANGLE and below MAX_SWIPE_ANGLE, we want to                
1192             // increase the touch slop to make it harder to begin scrolling the workspace. This          
1193             // results in vertically scrolling widgets to more easily. The higher the angle, the         
1194             // more we increase touch slop.                                                              
1195             theta -= START_DAMPING_TOUCH_SLOP_ANGLE;                                                     
1196             float extraRatio = (float)                                                                   
1197                     Math.sqrt((theta / (MAX_SWIPE_ANGLE - START_DAMPING_TOUCH_SLOP_ANGLE)));             
1198             super.determineScrollingStart(ev, 1 + TOUCH_SLOP_DAMPING_FACTOR * extraRatio);               
1199         } else {                                                                                         
1200             // Below START_DAMPING_TOUCH_SLOP_ANGLE, we don't do anything special                        
1201             super.determineScrollingStart(ev);                                                           
1202         }                                                                                                
1203     }                                                                                                    
1204                                                                                                          
1205     protected void onPageBeginMoving() {                                                                 
1206         super.onPageBeginMoving();                                                                       
1207                                                                                                          
1208         if (isHardwareAccelerated()) {                                                                   
1209             updateChildrenLayersEnabled(false);                                                          
1210         } else {                                                                                         
1211             if (mNextPage != INVALID_PAGE) {                                                             
1212                 // we're snapping to a particular screen                                                 
1213                 enableChildrenCache(mCurrentPage, mNextPage);                                            
1214             } else {                                                                                     
1215                 // this is when user is actively dragging a particular screen, they might                
1216                 // swipe it either left or right (but we won't advance by more than one screen)          
1217                 enableChildrenCache(mCurrentPage - 1, mCurrentPage + 1);                                 
1218             }                                                                                            
1219         }                                                                                                
1220     }                                                                                                    
1221                                                                                                          
1222     protected void onPageEndMoving() {                                                                   
1223         super.onPageEndMoving();                                                                         
1224                                                                                                          
1225         if (isHardwareAccelerated()) {                                                                   
1226             updateChildrenLayersEnabled(false);                                                          
1227         } else {                                                                                         
1228             clearChildrenCache();                                                                        
1229         }                                                                                                
1230                                                                                                          
1231         if (mDragController.isDragging()) {                                                              
1232             if (workspaceInModalState()) {                                                               
1233                 // If we are in springloaded mode, then force an event to check if the current touch     
1234                 // is under a new page (to scroll to)                                                    
1235                 mDragController.forceTouchMove();                                                        
1236             }                                                                                            
1237         }                                                                                                
1238                                                                                                          
1239         if (mDelayedResizeRunnable != null) {                                                            
1240             mDelayedResizeRunnable.run();                                                                
1241             mDelayedResizeRunnable = null;                                                               
1242         }                                                                                                
1243                                                                                                          
1244         if (mDelayedSnapToPageRunnable != null) {                                                        
1245             mDelayedSnapToPageRunnable.run();                                                            
1246             mDelayedSnapToPageRunnable = null;                                                           
1247         }                                                                                                
1248         if (mStripScreensOnPageStopMoving) {                                                             
1249             stripEmptyScreens();                                                                         
1250             mStripScreensOnPageStopMoving = false;                                                       
1251         }                                                                                                
1252     }                                                                                                    
1253                                                                                                          
1254     @Override                                                                                            
1255     protected void notifyPageSwitchListener() {                                                          
1256         super.notifyPageSwitchListener();                                                                
1257         Launcher.setScreen(getNextPage());                                                               
1258                                                                                                          
1259         if (hasCustomContent() && getNextPage() == 0 && !mCustomContentShowing) {                        
1260             mCustomContentShowing = true;                                                                
1261             if (mCustomContentCallbacks != null) {                                                       
1262                 mCustomContentCallbacks.onShow(false);                                                   
1263                 mCustomContentShowTime = System.currentTimeMillis();                                     
1264                 mLauncher.updateVoiceButtonProxyVisible(false);                                          
1265             }                                                                                            
1266         } else if (hasCustomContent() && getNextPage() != 0 && mCustomContentShowing) {                  
1267             mCustomContentShowing = false;                                                               
1268             if (mCustomContentCallbacks != null) {                                                       
1269                 mCustomContentCallbacks.onHide();                                                        
1270                 mLauncher.resetQSBScroll();                                                              
1271                 mLauncher.updateVoiceButtonProxyVisible(false);                                          
1272             }                                                                                            
1273         }                                                                                                
1274     }                                                                                                    
1275                                                                                                          
1276     protected CustomContentCallbacks getCustomContentCallbacks() {                                       
1277         return mCustomContentCallbacks;                                                                  
1278     }                                                                                                    
1279                                                                                                          
1280     protected void setWallpaperDimension() {                                                             
1281         new AsyncTask<Void, Void, Void>() {                                                              
1282             public Void doInBackground(Void ... args) {                                                  
1283                 String spKey = WallpaperCropActivity.getSharedPreferencesKey();                          
1284                 SharedPreferences sp =                                                                   
1285                         mLauncher.getSharedPreferences(spKey, Context.MODE_MULTI_PROCESS);               
1286                 LauncherWallpaperPickerActivity.suggestWallpaperDimension(mLauncher.getResources(),      
1287                         sp, mLauncher.getWindowManager(), mWallpaperManager,                             
1288                         mLauncher.overrideWallpaperDimensions());                                        
1289                 return null;                                                                             
1290             }                                                                                            
1291         }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);                                
1292     }                                                                                                    
1293                                                                                                          
1294     protected void snapToPage(int whichPage, Runnable r) {                                               
1295         snapToPage(whichPage, SLOW_PAGE_SNAP_ANIMATION_DURATION, r);                                     
1296     }                                                                                                    
1297                                                                                                          
1298     protected void snapToPage(int whichPage, int duration, Runnable r) {                                 
1299         if (mDelayedSnapToPageRunnable != null) {                                                        
1300             mDelayedSnapToPageRunnable.run();                                                            
1301         }                                                                                                
1302         mDelayedSnapToPageRunnable = r;                                                                  
1303         snapToPage(whichPage, duration);                                                                 
1304     }                                                                                                    
1305                                                                                                          
1306     public void snapToScreenId(long screenId) {                                                          
1307         snapToScreenId(screenId, null);                                                                  
1308     }                                                                                                    
1309                                                                                                          
1310     protected void snapToScreenId(long screenId, Runnable r) {                                           
1311         snapToPage(getPageIndexForScreenId(screenId), r);                                                
1312     }                                                                                                    
1313                                                                                                          
1314     class WallpaperOffsetInterpolator implements Choreographer.FrameCallback {                           
1315         float mFinalOffset = 0.0f;                                                                       
1316         float mCurrentOffset = 0.5f; // to force an initial update                                       
1317         boolean mWaitingForUpdate;                                                                       
1318         Choreographer mChoreographer;                                                                    
1319         Interpolator mInterpolator;                                                                      
1320         boolean mAnimating;                                                                              
1321         long mAnimationStartTime;                                                                        
1322         float mAnimationStartOffset;                                                                     
1323         private final int ANIMATION_DURATION = 250;                                                      
1324         // Don't use all the wallpaper for parallax until you have at least this many pages              
1325         private final int MIN_PARALLAX_PAGE_SPAN = 3;                                                    
1326         int mNumScreens;                                                                                 
1327                                                                                                          
1328         public WallpaperOffsetInterpolator() {                                                           
1329             mChoreographer = Choreographer.getInstance();                                                
1330             mInterpolator = new DecelerateInterpolator(1.5f);                                            
1331         }                                                                                                
1332                                                                                                          
1333         @Override                                                                                        
1334         public void doFrame(long frameTimeNanos) {                                                       
1335             updateOffset(false);                                                                         
1336         }                                                                                                
1337                                                                                                          
1338         private void updateOffset(boolean force) {                                                       
1339             if (mWaitingForUpdate || force) {                                                            
1340                 mWaitingForUpdate = false;                                                               
1341                 if (computeScrollOffset() && mWindowToken != null) {                                     
1342                     try {                                                                                
1343                         mWallpaperManager.setWallpaperOffsets(mWindowToken,                              
1344                                 mWallpaperOffset.getCurrX(), 0.5f);                                      
1345                         setWallpaperOffsetSteps();                                                       
1346                     } catch (IllegalArgumentException e) {                                               
1347                         Log.e(TAG, "Error updating wallpaper offset: " + e);                             
1348                     }                                                                                    
1349                 }                                                                                        
1350             }                                                                                            
1351         }                                                                                                
1352                                                                                                          
1353         public boolean computeScrollOffset() {                                                           
1354             final float oldOffset = mCurrentOffset;                                                      
1355             if (mAnimating) {                                                                            
1356                 long durationSinceAnimation = System.currentTimeMillis() - mAnimationStartTime;          
1357                 float t0 = durationSinceAnimation / (float) ANIMATION_DURATION;                          
1358                 float t1 = mInterpolator.getInterpolation(t0);                                           
1359                 mCurrentOffset = mAnimationStartOffset +                                                 
1360                         (mFinalOffset - mAnimationStartOffset) * t1;                                     
1361                 mAnimating = durationSinceAnimation < ANIMATION_DURATION;                                
1362             } else {                                                                                     
1363                 mCurrentOffset = mFinalOffset;                                                           
1364             }                                                                                            
1365                                                                                                          
1366             if (Math.abs(mCurrentOffset - mFinalOffset) > 0.0000001f) {                                  
1367                 scheduleUpdate();                                                                        
1368             }                                                                                            
1369             if (Math.abs(oldOffset - mCurrentOffset) > 0.0000001f) {                                     
1370                 return true;                                                                             
1371             }                                                                                            
1372             return false;                                                                                
1373         }                                                                                                
1374                                                                                                          
1375         private float wallpaperOffsetForCurrentScroll() {                                                
1376             if (getChildCount() <= 1) {                                                                  
1377                 return 0;                                                                                
1378             }                                                                                            
1379                                                                                                          
1380             // Exclude the leftmost page                                                                 
1381             int emptyExtraPages = numEmptyScreensToIgnore();                                             
1382             int firstIndex = numCustomPages();                                                           
1383             // Exclude the last extra empty screen (if we have > MIN_PARALLAX_PAGE_SPAN pages)           
1384             int lastIndex = getChildCount() - 1 - emptyExtraPages;                                       
1385             if (isLayoutRtl()) {                                                                         
1386                 int temp = firstIndex;                                                                   
1387                 firstIndex = lastIndex;                                                                  
1388                 lastIndex = temp;                                                                        
1389             }                                                                                            
1390                                                                                                          
1391             int firstPageScrollX = getScrollForPage(firstIndex);                                         
1392             int scrollRange = getScrollForPage(lastIndex) - firstPageScrollX;                            
1393             if (scrollRange == 0) {                                                                      
1394                 return 0;                                                                                
1395             } else {                                                                                     
1396                 // TODO: do different behavior if it's  a live wallpaper?                                
1397                 // Sometimes the left parameter of the pages is animated during a layout transition;     
1398                 // this parameter offsets it to keep the wallpaper from animating as well                
1399                 int adjustedScroll =                                                                     
1400                         getScrollX() - firstPageScrollX - getLayoutTransitionOffsetForPage(0);           
1401                 float offset = Math.min(1, adjustedScroll / (float) scrollRange);                        
1402                 offset = Math.max(0, offset);                                                            
1403                 // Don't use up all the wallpaper parallax until you have at least                       
1404                 // MIN_PARALLAX_PAGE_SPAN pages                                                          
1405                 int numScrollingPages = getNumScreensExcludingEmptyAndCustom();                          
1406                 int parallaxPageSpan;                                                                    
1407                 if (mWallpaperIsLiveWallpaper) {                                                         
1408                     parallaxPageSpan = numScrollingPages - 1;                                            
1409                 } else {                                                                                 
1410                     parallaxPageSpan = Math.max(MIN_PARALLAX_PAGE_SPAN, numScrollingPages - 1);          
1411                 }                                                                                        
1412                 mNumPagesForWallpaperParallax = parallaxPageSpan;                                        
1413                                                                                                          
1414                 // On RTL devices, push the wallpaper offset to the right if we don't have enough        
1415                 // pages (ie if numScrollingPages < MIN_PARALLAX_PAGE_SPAN)                              
1416                 int padding = isLayoutRtl() ? parallaxPageSpan - numScrollingPages + 1 : 0;              
1417                 return offset * (padding + numScrollingPages - 1) / parallaxPageSpan;                    
1418             }                                                                                            
1419         }                                                                                                
1420                                                                                                          
1421         private int numEmptyScreensToIgnore() {                                                          
1422             int numScrollingPages = getChildCount() - numCustomPages();                                  
1423             if (numScrollingPages >= MIN_PARALLAX_PAGE_SPAN && hasExtraEmptyScreen()) {                  
1424                 return 1;                                                                                
1425             } else {                                                                                     
1426                 return 0;                                                                                
1427             }                                                                                            
1428         }                                                                                                
1429                                                                                                          
1430         private int getNumScreensExcludingEmptyAndCustom() {                                             
1431             int numScrollingPages = getChildCount() - numEmptyScreensToIgnore() - numCustomPages();      
1432             return numScrollingPages;                                                                    
1433         }                                                                                                
1434                                                                                                          
1435         public void syncWithScroll() {                                                                   
1436             float offset = wallpaperOffsetForCurrentScroll();                                            
1437             mWallpaperOffset.setFinalX(offset);                                                          
1438             updateOffset(true);                                                                          
1439         }                                                                                                
1440                                                                                                          
1441         public float getCurrX() {                                                                        
1442             return mCurrentOffset;                                                                       
1443         }                                                                                                
1444                                                                                                          
1445         public float getFinalX() {                                                                       
1446             return mFinalOffset;                                                                         
1447         }                                                                                                
1448                                                                                                          
1449         private void animateToFinal() {                                                                  
1450             mAnimating = true;                                                                           
1451             mAnimationStartOffset = mCurrentOffset;                                                      
1452             mAnimationStartTime = System.currentTimeMillis();                                            
1453         }                                                                                                
1454                                                                                                          
1455         private void setWallpaperOffsetSteps() {                                                         
1456             // Set wallpaper offset steps (1 / (number of screens - 1))                                  
1457             float xOffset = 1.0f / mNumPagesForWallpaperParallax;                                        
1458             if (xOffset != mLastSetWallpaperOffsetSteps) {                                               
1459                 mWallpaperManager.setWallpaperOffsetSteps(xOffset, 1.0f);                                
1460                 mLastSetWallpaperOffsetSteps = xOffset;                                                  
1461             }                                                                                            
1462         }                                                                                                
1463                                                                                                          
1464         public void setFinalX(float x) {                                                                 
1465             scheduleUpdate();                                                                            
1466             mFinalOffset = Math.max(0f, Math.min(x, 1.0f));                                              
1467             if (getNumScreensExcludingEmptyAndCustom() != mNumScreens) {                                 
1468                 if (mNumScreens > 0) {                                                                   
1469                     // Don't animate if we're going from 0 screens                                       
1470                     animateToFinal();                                                                    
1471                 }                                                                                        
1472                 mNumScreens = getNumScreensExcludingEmptyAndCustom();                                    
1473             }                                                                                            
1474         }                                                                                                
1475                                                                                                          
1476         private void scheduleUpdate() {                                                                  
1477             if (!mWaitingForUpdate) {                                                                    
1478                 mChoreographer.postFrameCallback(this);                                                  
1479                 mWaitingForUpdate = true;                                                                
1480             }                                                                                            
1481         }                                                                                                
1482                                                                                                          
1483         public void jumpToFinal() {                                                                      
1484             mCurrentOffset = mFinalOffset;                                                               
1485         }                                                                                                
1486     }                                                                                                    
1487                                                                                                          
1488     @Override                                                                                            
1489     public void computeScroll() {                                                                        
1490         super.computeScroll();                                                                           
1491         mWallpaperOffset.syncWithScroll();                                                               
1492     }                                                                                                    
1493                                                                                                          
1494     @Override                                                                                            
1495     public void announceForAccessibility(CharSequence text) {                                            
1496         // Don't announce if apps is on top of us.                                                       
1497         if (!mLauncher.isAllAppsVisible()) {                                                             
1498             super.announceForAccessibility(text);                                                        
1499         }                                                                                                
1500     }                                                                                                    
1501                                                                                                          
1502     void showOutlines() {                                                                                
1503         if (!workspaceInModalState() && !mIsSwitchingState) {                                            
1504             if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();     
1505             if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();       
1506             mChildrenOutlineFadeInAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 1.0🔵
1507             mChildrenOutlineFadeInAnimation.setDuration(CHILDREN_OUTLINE_FADE_IN_DURATION);              
1508             mChildrenOutlineFadeInAnimation.start();                                                     
1509         }                                                                                                
1510     }                                                                                                    
1511                                                                                                          
1512     void hideOutlines() {                                                                                
1513         if (!workspaceInModalState() && !mIsSwitchingState) {                                            
1514             if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();       
1515             if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();     
1516             mChildrenOutlineFadeOutAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 0.🔵
1517             mChildrenOutlineFadeOutAnimation.setDuration(CHILDREN_OUTLINE_FADE_OUT_DURATION);            
1518             mChildrenOutlineFadeOutAnimation.setStartDelay(CHILDREN_OUTLINE_FADE_OUT_DELAY);             
1519             mChildrenOutlineFadeOutAnimation.start();                                                    
1520         }                                                                                                
1521     }                                                                                                    
1522                                                                                                          
1523     public void showOutlinesTemporarily() {                                                              
1524         if (!mIsPageMoving && !isTouchActive()) {                                                        
1525             snapToPage(mCurrentPage);                                                                    
1526         }                                                                                                
1527     }                                                                                                    
1528                                                                                                          
1529     public void setChildrenOutlineAlpha(float alpha) {                                                   
1530         mChildrenOutlineAlpha = alpha;                                                                   
1531         for (int i = 0; i < getChildCount(); i++) {                                                      
1532             CellLayout cl = (CellLayout) getChildAt(i);                                                  
1533             cl.setBackgroundAlpha(alpha);                                                                
1534         }                                                                                                
1535     }                                                                                                    
1536                                                                                                          
1537     public float getChildrenOutlineAlpha() {                                                             
1538         return mChildrenOutlineAlpha;                                                                    
1539     }                                                                                                    
1540                                                                                                          
1541     private void animateBackgroundGradient(float finalAlpha, boolean animated) {                         
1542         final DragLayer dragLayer = mLauncher.getDragLayer();                                            
1543                                                                                                          
1544         if (mBackgroundFadeInAnimation != null) {                                                        
1545             mBackgroundFadeInAnimation.cancel();                                                         
1546             mBackgroundFadeInAnimation = null;                                                           
1547         }                                                                                                
1548         if (mBackgroundFadeOutAnimation != null) {                                                       
1549             mBackgroundFadeOutAnimation.cancel();                                                        
1550             mBackgroundFadeOutAnimation = null;                                                          
1551         }                                                                                                
1552         float startAlpha = dragLayer.getBackgroundAlpha();                                               
1553         if (finalAlpha != startAlpha) {                                                                  
1554             if (animated) {                                                                              
1555                 mBackgroundFadeOutAnimation =                                                            
1556                         LauncherAnimUtils.ofFloat(this, startAlpha, finalAlpha);                         
1557                 mBackgroundFadeOutAnimation.addUpdateListener(new AnimatorUpdateListener() {             
1558                     public void onAnimationUpdate(ValueAnimator animation) {                             
1559                         dragLayer.setBackgroundAlpha(                                                    
1560                                 ((Float)animation.getAnimatedValue()).floatValue());                     
1561                     }                                                                                    
1562                 });                                                                                      
1563                 mBackgroundFadeOutAnimation.setInterpolator(new DecelerateInterpolator(1.5f));           
1564                 mBackgroundFadeOutAnimation.setDuration(BACKGROUND_FADE_OUT_DURATION);                   
1565                 mBackgroundFadeOutAnimation.start();                                                     
1566             } else {                                                                                     
1567                 dragLayer.setBackgroundAlpha(finalAlpha);                                                
1568             }                                                                                            
1569         }                                                                                                
1570     }                                                                                                    
1571                                                                                                          
1572     float backgroundAlphaInterpolator(float r) {                                                         
1573         float pivotA = 0.1f;                                                                             
1574         float pivotB = 0.4f;                                                                             
1575         if (r < pivotA) {                                                                                
1576             return 0;                                                                                    
1577         } else if (r > pivotB) {                                                                         
1578             return 1.0f;                                                                                 
1579         } else {                                                                                         
1580             return (r - pivotA)/(pivotB - pivotA);                                                       
1581         }                                                                                                
1582     }                                                                                                    
1583                                                                                                          
1584     private void updatePageAlphaValues(int screenCenter) {                                               
1585         boolean isInOverscroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX;                         
1586         if (mWorkspaceFadeInAdjacentScreens &&                                                           
1587                 !workspaceInModalState() &&                                                              
1588                 !mIsSwitchingState &&                                                                    
1589                 !isInOverscroll) {                                                                       
1590             for (int i = numCustomPages(); i < getChildCount(); i++) {                                   
1591                 CellLayout child = (CellLayout) getChildAt(i);                                           
1592                 if (child != null) {                                                                     
1593                     float scrollProgress = getScrollProgress(screenCenter, child, i);                    
1594                     float alpha = 1 - Math.abs(scrollProgress);                                          
1595                     child.getShortcutsAndWidgets().setAlpha(alpha);                                      
1596                     //child.setBackgroundAlphaMultiplier(1 - alpha);                                     
1597                 }                                                                                        
1598             }                                                                                            
1599         }                                                                                                
1600     }                                                                                                    
1601                                                                                                          
1602     private void setChildrenBackgroundAlphaMultipliers(float a) {                                        
1603         for (int i = 0; i < getChildCount(); i++) {                                                      
1604             CellLayout child = (CellLayout) getChildAt(i);                                               
1605             child.setBackgroundAlphaMultiplier(a);                                                       
1606         }                                                                                                
1607     }                                                                                                    
1608                                                                                                          
1609     public boolean hasCustomContent() {                                                                  
1610         return (mScreenOrder.size() > 0 && mScreenOrder.get(0) == CUSTOM_CONTENT_SCREEN_ID);             
1611     }                                                                                                    
1612                                                                                                          
1613     public int numCustomPages() {                                                                        
1614         return hasCustomContent() ? 1 : 0;                                                               
1615     }                                                                                                    
1616                                                                                                          
1617     public boolean isOnOrMovingToCustomContent() {                                                       
1618         return hasCustomContent() && getNextPage() == 0;                                                 
1619     }                                                                                                    
1620                                                                                                          
1621     private void updateStateForCustomContent(int screenCenter) {                                         
1622         float translationX = 0;                                                                          
1623         float progress = 0;                                                                              
1624         if (hasCustomContent()) {                                                                        
1625             int index = mScreenOrder.indexOf(CUSTOM_CONTENT_SCREEN_ID);                                  
1626                                                                                                          
1627             int scrollDelta = getScrollX() - getScrollForPage(index) -                                   
1628                     getLayoutTransitionOffsetForPage(index);                                             
1629             float scrollRange = getScrollForPage(index + 1) - getScrollForPage(index);                   
1630             translationX = scrollRange - scrollDelta;                                                    
1631             progress = (scrollRange - scrollDelta) / scrollRange;                                        
1632                                                                                                          
1633             if (isLayoutRtl()) {                                                                         
1634                 translationX = Math.min(0, translationX);                                                
1635             } else {                                                                                     
1636                 translationX = Math.max(0, translationX);                                                
1637             }                                                                                            
1638             progress = Math.max(0, progress);                                                            
1639         }                                                                                                
1640                                                                                                          
1641         if (Float.compare(progress, mLastCustomContentScrollProgress) == 0) return;                      
1642                                                                                                          
1643         CellLayout cc = mWorkspaceScreens.get(CUSTOM_CONTENT_SCREEN_ID);                                 
1644         if (progress > 0 && cc.getVisibility() != VISIBLE && !workspaceInModalState()) {                 
1645             cc.setVisibility(VISIBLE);                                                                   
1646         }                                                                                                
1647                                                                                                          
1648         mLastCustomContentScrollProgress = progress;                                                     
1649                                                                                                          
1650         mLauncher.getDragLayer().setBackgroundAlpha(progress * 0.8f);                                    
1651                                                                                                          
1652         if (mLauncher.getHotseat() != null) {                                                            
1653             mLauncher.getHotseat().setTranslationX(translationX);                                        
1654         }                                                                                                
1655                                                                                                          
1656         if (getPageIndicator() != null) {                                                                
1657             getPageIndicator().setTranslationX(translationX);                                            
1658         }                                                                                                
1659                                                                                                          
1660         if (mCustomContentCallbacks != null) {                                                           
1661             mCustomContentCallbacks.onScrollProgressChanged(progress);                                   
1662         }                                                                                                
1663     }                                                                                                    
1664                                                                                                          
1665     @Override                                                                                            
1666     protected OnClickListener getPageIndicatorClickListener() {                                          
1667         AccessibilityManager am = (AccessibilityManager)                                                 
1668                 getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);                            
1669         if (!am.isTouchExplorationEnabled()) {                                                           
1670             return null;                                                                                 
1671         }                                                                                                
1672         OnClickListener listener = new OnClickListener() {                                               
1673             @Override                                                                                    
1674             public void onClick(View arg0) {                                                             
1675                 enterOverviewMode();                                                                     
1676             }                                                                                            
1677         };                                                                                               
1678         return listener;                                                                                 
1679     }                                                                                                    
1680                                                                                                          
1681     @Override                                                                                            
1682     protected void screenScrolled(int screenCenter) {                                                    
1683         final boolean isRtl = isLayoutRtl();                                                             
1684         super.screenScrolled(screenCenter);                                                              
1685                                                                                                          
1686         updatePageAlphaValues(screenCenter);                                                             
1687         updateStateForCustomContent(screenCenter);                                                       
1688         enableHwLayersOnVisiblePages();                                                                  
1689                                                                                                          
1690         boolean shouldOverScroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX;                       
1691                                                                                                          
1692         if (shouldOverScroll) {                                                                          
1693             int index = 0;                                                                               
1694             final int lowerIndex = 0;                                                                    
1695             final int upperIndex = getChildCount() - 1;                                                  
1696                                                                                                          
1697             final boolean isLeftPage = mOverScrollX < 0;                                                 
1698             index = (!isRtl && isLeftPage) || (isRtl && !isLeftPage) ? lowerIndex : upperIndex;          
1699                                                                                                          
1700             CellLayout cl = (CellLayout) getChildAt(index);                                              
1701             float effect = Math.abs(mOverScrollEffect);                                                  
1702             cl.setOverScrollAmount(Math.abs(effect), isLeftPage);                                        
1703                                                                                                          
1704             mOverscrollEffectSet = true;                                                                 
1705         } else {                                                                                         
1706             if (mOverscrollEffectSet && getChildCount() > 0) {                                           
1707                 mOverscrollEffectSet = false;                                                            
1708                 ((CellLayout) getChildAt(0)).setOverScrollAmount(0, false);                              
1709                 ((CellLayout) getChildAt(getChildCount() - 1)).setOverScrollAmount(0, false);            
1710             }                                                                                            
1711         }                                                                                                
1712     }                                                                                                    
1713                                                                                                          
1714     @Override                                                                                            
1715     protected void overScroll(float amount) {                                                            
1716         boolean shouldOverScroll = (amount < 0 && (!hasCustomContent() || isLayoutRtl())) ||             
1717                 (amount > 0 && (!hasCustomContent() || !isLayoutRtl()));                                 
1718         if (shouldOverScroll) {                                                                          
1719             dampedOverScroll(amount);                                                                    
1720             mOverScrollEffect = acceleratedOverFactor(amount);                                           
1721         } else {                                                                                         
1722             mOverScrollEffect = 0;                                                                       
1723         }                                                                                                
1724     }                                                                                                    
1725                                                                                                          
1726     protected void onAttachedToWindow() {                                                                
1727         super.onAttachedToWindow();                                                                      
1728         mWindowToken = getWindowToken();                                                                 
1729         computeScroll();                                                                                 
1730         mDragController.setWindowToken(mWindowToken);                                                    
1731     }                                                                                                    
1732                                                                                                          
1733     protected void onDetachedFromWindow() {                                                              
1734         super.onDetachedFromWindow();                                                                    
1735         mWindowToken = null;                                                                             
1736     }                                                                                                    
1737                                                                                                          
1738     protected void onResume() {                                                                          
1739         if (getPageIndicator() != null) {                                                                
1740             // In case accessibility state has changed, we need to perform this on every                 
1741             // attach to window                                                                          
1742             OnClickListener listener = getPageIndicatorClickListener();                                  
1743             if (listener != null) {                                                                      
1744                 getPageIndicator().setOnClickListener(listener);                                         
1745             }                                                                                            
1746         }                                                                                                
1747         AccessibilityManager am = (AccessibilityManager)                                                 
1748                 getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);                            
1749         sAccessibilityEnabled = am.isEnabled();                                                          
1750                                                                                                          
1751         // Update wallpaper dimensions if they were changed since last onResume                          
1752         // (we also always set the wallpaper dimensions in the constructor)                              
1753         if (LauncherAppState.getInstance().hasWallpaperChangedSinceLastCheck()) {                        
1754             setWallpaperDimension();                                                                     
1755         }                                                                                                
1756         mWallpaperIsLiveWallpaper = mWallpaperManager.getWallpaperInfo() != null;                        
1757         // Force the wallpaper offset steps to be set again, because another app might have changed      
1758         // them                                                                                          
1759         mLastSetWallpaperOffsetSteps = 0f;                                                               
1760     }                                                                                                    
1761                                                                                                          
1762     @Override                                                                                            
1763     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {                 
1764         if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) {                       
1765             mWallpaperOffset.syncWithScroll();                                                           
1766             mWallpaperOffset.jumpToFinal();                                                              
1767         }                                                                                                
1768         super.onLayout(changed, left, top, right, bottom);                                               
1769     }                                                                                                    
1770                                                                                                          
1771     @Override                                                                                            
1772     protected void onDraw(Canvas canvas) {                                                               
1773         super.onDraw(canvas);                                                                            
1774                                                                                                          
1775         // Call back to LauncherModel to finish binding after the first draw                             
1776         post(mBindPages);                                                                                
1777     }                                                                                                    
1778                                                                                                          
1779     @Override                                                                                            
1780     protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {           
1781         if (!mLauncher.isAllAppsVisible()) {                                                             
1782             final Folder openFolder = getOpenFolder();                                                   
1783             if (openFolder != null) {                                                                    
1784                 return openFolder.requestFocus(direction, previouslyFocusedRect);                        
1785             } else {                                                                                     
1786                 return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);              
1787             }                                                                                            
1788         }                                                                                                
1789         return false;                                                                                    
1790     }                                                                                                    
1791                                                                                                          
1792     @Override                                                                                            
1793     public int getDescendantFocusability() {                                                             
1794         if (workspaceInModalState()) {                                                                   
1795             return ViewGroup.FOCUS_BLOCK_DESCENDANTS;                                                    
1796         }                                                                                                
1797         return super.getDescendantFocusability();                                                        
1798     }                                                                                                    
1799                                                                                                          
1800     @Override                                                                                            
1801     public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {                 
1802         if (!mLauncher.isAllAppsVisible()) {                                                             
1803             final Folder openFolder = getOpenFolder();                                                   
1804             if (openFolder != null) {                                                                    
1805                 openFolder.addFocusables(views, direction);                                              
1806             } else {                                                                                     
1807                 super.addFocusables(views, direction, focusableMode);                                    
1808             }                                                                                            
1809         }                                                                                                
1810     }                                                                                                    
1811                                                                                                          
1812     public boolean workspaceInModalState() {                                                             
1813         return mState != State.NORMAL;                                                                   
1814     }                                                                                                    
1815                                                                                                          
1816     void enableChildrenCache(int fromPage, int toPage) {                                                 
1817         if (fromPage > toPage) {                                                                         
1818             final int temp = fromPage;                                                                   
1819             fromPage = toPage;                                                                           
1820             toPage = temp;                                                                               
1821         }                                                                                                
1822                                                                                                          
1823         final int screenCount = getChildCount();                                                         
1824                                                                                                          
1825         fromPage = Math.max(fromPage, 0);                                                                
1826         toPage = Math.min(toPage, screenCount - 1);                                                      
1827                                                                                                          
1828         for (int i = fromPage; i <= toPage; i++) {                                                       
1829             final CellLayout layout = (CellLayout) getChildAt(i);                                        
1830             layout.setChildrenDrawnWithCacheEnabled(true);                                               
1831             layout.setChildrenDrawingCacheEnabled(true);                                                 
1832         }                                                                                                
1833     }                                                                                                    
1834                                                                                                          
1835     void clearChildrenCache() {                                                                          
1836         final int screenCount = getChildCount();                                                         
1837         for (int i = 0; i < screenCount; i++) {                                                          
1838             final CellLayout layout = (CellLayout) getChildAt(i);                                        
1839             layout.setChildrenDrawnWithCacheEnabled(false);                                              
1840             // In software mode, we don't want the items to continue to be drawn into bitmaps            
1841             if (!isHardwareAccelerated()) {                                                              
1842                 layout.setChildrenDrawingCacheEnabled(false);                                            
1843             }                                                                                            
1844         }                                                                                                
1845     }                                                                                                    
1846                                                                                                          
1847     private void updateChildrenLayersEnabled(boolean force) {                                            
1848         boolean small = mState == State.OVERVIEW || mIsSwitchingState;                                   
1849         boolean enableChildrenLayers = force || small || mAnimatingViewIntoPlace || isPageMoving();      
1850                                                                                                          
1851         if (enableChildrenLayers != mChildrenLayersEnabled) {                                            
1852             mChildrenLayersEnabled = enableChildrenLayers;                                               
1853             if (mChildrenLayersEnabled) {                                                                
1854                 enableHwLayersOnVisiblePages();                                                          
1855             } else {                                                                                     
1856                 for (int i = 0; i < getPageCount(); i++) {                                               
1857                     final CellLayout cl = (CellLayout) getChildAt(i);                                    
1858                     cl.enableHardwareLayer(false);                                                       
1859                 }                                                                                        
1860             }                                                                                            
1861         }                                                                                                
1862     }                                                                                                    
1863                                                                                                          
1864     private void enableHwLayersOnVisiblePages() {                                                        
1865         if (mChildrenLayersEnabled) {                                                                    
1866             final int screenCount = getChildCount();                                                     
1867             getVisiblePages(mTempVisiblePagesRange);                                                     
1868             int leftScreen = mTempVisiblePagesRange[0];                                                  
1869             int rightScreen = mTempVisiblePagesRange[1];                                                 
1870             if (leftScreen == rightScreen) {                                                             
1871                 // make sure we're caching at least two pages always                                     
1872                 if (rightScreen < screenCount - 1) {                                                     
1873                     rightScreen++;                                                                       
1874                 } else if (leftScreen > 0) {                                                             
1875                     leftScreen--;                                                                        
1876                 }                                                                                        
1877             }                                                                                            
1878                                                                                                          
1879             final CellLayout customScreen = mWorkspaceScreens.get(CUSTOM_CONTENT_SCREEN_ID);             
1880             for (int i = 0; i < screenCount; i++) {                                                      
1881                 final CellLayout layout = (CellLayout) getPageAt(i);                                     
1882                                                                                                          
1883                 // enable layers between left and right screen inclusive, except for the                 
1884                 // customScreen, which may animate its content during transitions.                       
1885                 boolean enableLayer = layout != customScreen &&                                          
1886                         leftScreen <= i && i <= rightScreen && shouldDrawChild(layout);                  
1887                 layout.enableHardwareLayer(enableLayer);                                                 
1888             }                                                                                            
1889         }                                                                                                
1890     }                                                                                                    
1891                                                                                                          
1892     public void buildPageHardwareLayers() {                                                              
1893         // force layers to be enabled just for the call to buildLayer                                    
1894         updateChildrenLayersEnabled(true);                                                               
1895         if (getWindowToken() != null) {                                                                  
1896             final int childCount = getChildCount();                                                      
1897             for (int i = 0; i < childCount; i++) {                                                       
1898                 CellLayout cl = (CellLayout) getChildAt(i);                                              
1899                 cl.buildHardwareLayer();                                                                 
1900             }                                                                                            
1901         }                                                                                                
1902         updateChildrenLayersEnabled(false);                                                              
1903     }                                                                                                    
1904                                                                                                          
1905     protected void onWallpaperTap(MotionEvent ev) {                                                      
1906         final int[] position = mTempCell;                                                                
1907         getLocationOnScreen(position);                                                                   
1908                                                                                                          
1909         int pointerIndex = ev.getActionIndex();                                                          
1910         position[0] += (int) ev.getX(pointerIndex);                                                      
1911         position[1] += (int) ev.getY(pointerIndex);                                                      
1912                                                                                                          
1913         mWallpaperManager.sendWallpaperCommand(getWindowToken(),                                         
1914                 ev.getAction() == MotionEvent.ACTION_UP                                                  
1915                         ? WallpaperManager.COMMAND_TAP : WallpaperManager.COMMAND_SECONDARY_TAP,         
1916                 position[0], position[1], 0, null);                                                      
1917     }                                                                                                    
1918                                                                                                          
1919     /*                                                                                                   
1920      * This interpolator emulates the rate at which the perceived scale of an object changes             
1921      * as its distance from a camera increases. When this interpolator is applied to a scale             
1922      * animation on a view, it evokes the sense that the object is shrinking due to moving away          
1923      * from the camera.                                                                                  
1924      */                                                                                                  
1925     static class ZInterpolator implements TimeInterpolator {                                             
1926         private float focalLength;                                                                       
1927                                                                                                          
1928         public ZInterpolator(float foc) {                                                                
1929             focalLength = foc;                                                                           
1930         }                                                                                                
1931                                                                                                          
1932         public float getInterpolation(float input) {                                                     
1933             return (1.0f - focalLength / (focalLength + input)) /                                        
1934                 (1.0f - focalLength / (focalLength + 1.0f));                                             
1935         }                                                                                                
1936     }                                                                                                    
1937                                                                                                          
1938     /*                                                                                                   
1939      * The exact reverse of ZInterpolator.                                                               
1940      */                                                                                                  
1941     static class InverseZInterpolator implements TimeInterpolator {                                      
1942         private ZInterpolator zInterpolator;                                                             
1943         public InverseZInterpolator(float foc) {                                                         
1944             zInterpolator = new ZInterpolator(foc);                                                      
1945         }                                                                                                
1946         public float getInterpolation(float input) {                                                     
1947             return 1 - zInterpolator.getInterpolation(1 - input);                                        
1948         }                                                                                                
1949     }                                                                                                    
1950                                                                                                          
1951     /*                                                                                                   
1952      * ZInterpolator compounded with an ease-out.                                                        
1953      */                                                                                                  
1954     static class ZoomOutInterpolator implements TimeInterpolator {                                       
1955         private final DecelerateInterpolator decelerate = new DecelerateInterpolator(0.75f);             
1956         private final ZInterpolator zInterpolator = new ZInterpolator(0.13f);                            
1957                                                                                                          
1958         public float getInterpolation(float input) {                                                     
1959             return decelerate.getInterpolation(zInterpolator.getInterpolation(input));                   
1960         }                                                                                                
1961     }                                                                                                    
1962                                                                                                          
1963     /*                                                                                                   
1964      * InvereZInterpolator compounded with an ease-out.                                                  
1965      */                                                                                                  
1966     static class ZoomInInterpolator implements TimeInterpolator {                                        
1967         private final InverseZInterpolator inverseZInterpolator = new InverseZInterpolator(0.35f);       
1968         private final DecelerateInterpolator decelerate = new DecelerateInterpolator(3.0f);              
1969                                                                                                          
1970         public float getInterpolation(float input) {                                                     
1971             return decelerate.getInterpolation(inverseZInterpolator.getInterpolation(input));            
1972         }                                                                                                
1973     }                                                                                                    
1974                                                                                                          
1975     private final ZoomInInterpolator mZoomInInterpolator = new ZoomInInterpolator();                     
1976                                                                                                          
1977     /*                                                                                                   
1978     *                                                                                                    
1979     * We call these methods (onDragStartedWithItemSpans/onDragStartedWithSize) whenever we               
1980     * start a drag in Launcher, regardless of whether the drag has ever entered the Workspace            
1981     *                                                                                                    
1982     * These methods mark the appropriate pages as accepting drops (which alters their visual             
1983     * appearance).                                                                                       
1984     *                                                                                                    
1985     */                                                                                                   
1986     private static Rect getDrawableBounds(Drawable d) {                                                  
1987         Rect bounds = new Rect();                                                                        
1988         d.copyBounds(bounds);                                                                            
1989         if (bounds.width() == 0 || bounds.height() == 0) {                                               
1990             bounds.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());                             
1991         } else {                                                                                         
1992             bounds.offsetTo(0, 0);                                                                       
1993         }                                                                                                
1994         if (d instanceof PreloadIconDrawable) {                                                          
1995             int inset = -((PreloadIconDrawable) d).getOutset();                                          
1996             bounds.inset(inset, inset);                                                                  
1997         }                                                                                                
1998         return bounds;                                                                                   
1999     }                                                                                                    
2000                                                                                                          
2001     public void onExternalDragStartedWithItem(View v) {                                                  
2002         // Compose a drag bitmap with the view scaled to the icon size                                   
2003         LauncherAppState app = LauncherAppState.getInstance();                                           
2004         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                    
2005         int iconSize = grid.iconSizePx;                                                                  
2006         int bmpWidth = v.getMeasuredWidth();                                                             
2007         int bmpHeight = v.getMeasuredHeight();                                                           
2008                                                                                                          
2009         // If this is a text view, use its drawable instead                                              
2010         if (v instanceof TextView) {                                                                     
2011             TextView tv = (TextView) v;                                                                  
2012             Drawable d = tv.getCompoundDrawables()[1];                                                   
2013             Rect bounds = getDrawableBounds(d);                                                          
2014             bmpWidth = bounds.width();                                                                   
2015             bmpHeight = bounds.height();                                                                 
2016         }                                                                                                
2017                                                                                                          
2018         // Compose the bitmap to create the icon from                                                    
2019         Bitmap b = Bitmap.createBitmap(bmpWidth, bmpHeight,                                              
2020                 Bitmap.Config.ARGB_8888);                                                                
2021         mCanvas.setBitmap(b);                                                                            
2022         drawDragView(v, mCanvas, 0);                                                                     
2023         mCanvas.setBitmap(null);                                                                         
2024                                                                                                          
2025         // The outline is used to visualize where the item will land if dropped                          
2026         mDragOutline = createDragOutline(b, DRAG_BITMAP_PADDING, iconSize, iconSize, true);              
2027     }                                                                                                    
2028                                                                                                          
2029     public void onDragStartedWithItem(PendingAddItemInfo info, Bitmap b, boolean clipAlpha) {            
2030         int[] size = estimateItemSize(info.spanX, info.spanY, info, false);                              
2031                                                                                                          
2032         // The outline is used to visualize where the item will land if dropped                          
2033         mDragOutline = createDragOutline(b, DRAG_BITMAP_PADDING, size[0], size[1], clipAlpha);           
2034     }                                                                                                    
2035                                                                                                          
2036     public void exitWidgetResizeMode() {                                                                 
2037         DragLayer dragLayer = mLauncher.getDragLayer();                                                  
2038         dragLayer.clearAllResizeFrames();                                                                
2039     }                                                                                                    
2040                                                                                                          
2041     private void initAnimationArrays() {                                                                 
2042         final int childCount = getChildCount();                                                          
2043         if (mLastChildCount == childCount) return;                                                       
2044                                                                                                          
2045         mOldBackgroundAlphas = new float[childCount];                                                    
2046         mOldAlphas = new float[childCount];                                                              
2047         mNewBackgroundAlphas = new float[childCount];                                                    
2048         mNewAlphas = new float[childCount];                                                              
2049     }                                                                                                    
2050                                                                                                          
2051     Animator getChangeStateAnimation(final State state, boolean animated,                                
2052             ArrayList<View> layerViews) {                                                                
2053         return getChangeStateAnimation(state, animated, 0, -1, layerViews);                              
2054     }                                                                                                    
2055                                                                                                          
2056     @Override                                                                                            
2057     protected void getFreeScrollPageRange(int[] range) {                                                 
2058         getOverviewModePages(range);                                                                     
2059     }                                                                                                    
2060                                                                                                          
2061     private void getOverviewModePages(int[] range) {                                                     
2062         int start = numCustomPages();                                                                    
2063         int end = getChildCount() - 1;                                                                   
2064                                                                                                          
2065         range[0] = Math.max(0, Math.min(start, getChildCount() - 1));                                    
2066         range[1] = Math.max(0,  end);                                                                    
2067     }                                                                                                    
2068                                                                                                          
2069     protected void onStartReordering() {                                                                 
2070         super.onStartReordering();                                                                       
2071         showOutlines();                                                                                  
2072         // Reordering handles its own animations, disable the automatic ones.                            
2073         disableLayoutTransitions();                                                                      
2074     }                                                                                                    
2075                                                                                                          
2076     protected void onEndReordering() {                                                                   
2077         super.onEndReordering();                                                                         
2078                                                                                                          
2079         if (mLauncher.isWorkspaceLoading()) {                                                            
2080             // Invalid and dangerous operation if workspace is loading                                   
2081             return;                                                                                      
2082         }                                                                                                
2083                                                                                                          
2084         hideOutlines();                                                                                  
2085         mScreenOrder.clear();                                                                            
2086         int count = getChildCount();                                                                     
2087         for (int i = 0; i < count; i++) {                                                                
2088             CellLayout cl = ((CellLayout) getChildAt(i));                                                
2089             mScreenOrder.add(getIdForScreen(cl));                                                        
2090         }                                                                                                
2091                                                                                                          
2092         mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder);                        
2093                                                                                                          
2094         // Re-enable auto layout transitions for page deletion.                                          
2095         enableLayoutTransitions();                                                                       
2096     }                                                                                                    
2097                                                                                                          
2098     public boolean isInOverviewMode() {                                                                  
2099         return mState == State.OVERVIEW;                                                                 
2100     }                                                                                                    
2101                                                                                                          
2102     public boolean enterOverviewMode() {                                                                 
2103         if (mTouchState != TOUCH_STATE_REST) {                                                           
2104             return false;                                                                                
2105         }                                                                                                
2106         enableOverviewMode(true, -1, true);                                                              
2107         return true;                                                                                     
2108     }                                                                                                    
2109                                                                                                          
2110     public void exitOverviewMode(boolean animated) {                                                     
2111         exitOverviewMode(-1, animated);                                                                  
2112     }                                                                                                    
2113                                                                                                          
2114     public void exitOverviewMode(int snapPage, boolean animated) {                                       
2115         enableOverviewMode(false, snapPage, animated);                                                   
2116     }                                                                                                    
2117                                                                                                          
2118     private void enableOverviewMode(boolean enable, int snapPage, boolean animated) {                    
2119         State finalState = Workspace.State.OVERVIEW;                                                     
2120         if (!enable) {                                                                                   
2121             finalState = Workspace.State.NORMAL;                                                         
2122         }                                                                                                
2123                                                                                                          
2124         Animator workspaceAnim = getChangeStateAnimation(finalState, animated, 0, snapPage);             
2125         if (workspaceAnim != null) {                                                                     
2126             onTransitionPrepare();                                                                       
2127             workspaceAnim.addListener(new AnimatorListenerAdapter() {                                    
2128                 @Override                                                                                
2129                 public void onAnimationEnd(Animator arg0) {                                              
2130                     onTransitionEnd();                                                                   
2131                 }                                                                                        
2132             });                                                                                          
2133             workspaceAnim.start();                                                                       
2134         }                                                                                                
2135     }                                                                                                    
2136                                                                                                          
2137     int getOverviewModeTranslationY() {                                                                  
2138         LauncherAppState app = LauncherAppState.getInstance();                                           
2139         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                    
2140         Rect overviewBar = grid.getOverviewModeButtonBarRect();                                          
2141                                                                                                          
2142         int availableHeight = getViewportHeight();                                                       
2143         int scaledHeight = (int) (mOverviewModeShrinkFactor * getNormalChildHeight());                   
2144         int offsetFromTopEdge = (availableHeight - scaledHeight) / 2;                                    
2145         int offsetToCenterInOverview = (availableHeight - mInsets.top - overviewBar.height()             
2146                 - scaledHeight) / 2;                                                                     
2147                                                                                                          
2148         return -offsetFromTopEdge + mInsets.top + offsetToCenterInOverview;                              
2149     }                                                                                                    
2150                                                                                                          
2151     boolean shouldVoiceButtonProxyBeVisible() {                                                          
2152         if (isOnOrMovingToCustomContent()) {                                                             
2153             return false;                                                                                
2154         }                                                                                                
2155         if (mState != State.NORMAL) {                                                                    
2156             return false;                                                                                
2157         }                                                                                                
2158         return true;                                                                                     
2159     }                                                                                                    
2160                                                                                                          
2161     public void updateInteractionForState() {                                                            
2162         if (mState != State.NORMAL) {                                                                    
2163             mLauncher.onInteractionBegin();                                                              
2164         } else {                                                                                         
2165             mLauncher.onInteractionEnd();                                                                
2166         }                                                                                                
2167     }                                                                                                    
2168                                                                                                          
2169     private void setState(State state) {                                                                 
2170         mState = state;                                                                                  
2171         updateInteractionForState();                                                                     
2172         updateAccessibilityFlags();                                                                      
2173     }                                                                                                    
2174                                                                                                          
2175     State getState() {                                                                                   
2176         return mState;                                                                                   
2177     }                                                                                                    
2178                                                                                                          
2179     private void updateAccessibilityFlags() {                                                            
2180         int accessible = mState == State.NORMAL ?                                                        
2181                 ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES :                                             
2182                 ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS;                              
2183         setImportantForAccessibility(accessible);                                                        
2184     }                                                                                                    
2185                                                                                                          
2186     private static final int HIDE_WORKSPACE_DURATION = 100;                                              
2187                                                                                                          
2188     Animator getChangeStateAnimation(final State state, boolean animated, int delay, int snapPage) {     
2189         return getChangeStateAnimation(state, animated, delay, snapPage, null);                          
2190     }                                                                                                    
2191                                                                                                          
2192     Animator getChangeStateAnimation(final State state, boolean animated, int delay, int snapPage,       
2193             ArrayList<View> layerViews) {                                                                
2194         if (mState == state) {                                                                           
2195             return null;                                                                                 
2196         }                                                                                                
2197                                                                                                          
2198         // Initialize animation arrays for the first time if necessary                                   
2199         initAnimationArrays();                                                                           
2200                                                                                                          
2201         AnimatorSet anim = animated ? LauncherAnimUtils.createAnimatorSet() : null;                      
2202                                                                                                          
2203         final State oldState = mState;                                                                   
2204         final boolean oldStateIsNormal = (oldState == State.NORMAL);                                     
2205         final boolean oldStateIsSpringLoaded = (oldState == State.SPRING_LOADED);                        
2206         final boolean oldStateIsNormalHidden = (oldState == State.NORMAL_HIDDEN);                        
2207         final boolean oldStateIsOverviewHidden = (oldState == State.OVERVIEW_HIDDEN);                    
2208         final boolean oldStateIsOverview = (oldState == State.OVERVIEW);                                 
2209         setState(state);                                                                                 
2210         final boolean stateIsNormal = (state == State.NORMAL);                                           
2211         final boolean stateIsSpringLoaded = (state == State.SPRING_LOADED);                              
2212         final boolean stateIsNormalHidden = (state == State.NORMAL_HIDDEN);                              
2213         final boolean stateIsOverviewHidden = (state == State.OVERVIEW_HIDDEN);                          
2214         final boolean stateIsOverview = (state == State.OVERVIEW);                                       
2215         float finalBackgroundAlpha = (stateIsSpringLoaded || stateIsOverview) ? 1.0f : 0f;               
2216         float finalHotseatAndPageIndicatorAlpha = (stateIsNormal || stateIsSpringLoaded) ? 1f : 0f;      
2217         float finalOverviewPanelAlpha = stateIsOverview ? 1f : 0f;                                       
2218         float finalSearchBarAlpha = !stateIsNormal ? 0f : 1f;                                            
2219         float finalWorkspaceTranslationY = stateIsOverview || stateIsOverviewHidden ?                    
2220                 getOverviewModeTranslationY() : 0;                                                       
2221                                                                                                          
2222         boolean workspaceToAllApps = (oldStateIsNormal && stateIsNormalHidden);                          
2223         boolean overviewToAllApps = (oldStateIsOverview && stateIsOverviewHidden);                       
2224         boolean allAppsToWorkspace = (stateIsNormalHidden && stateIsNormal);                             
2225         boolean workspaceToOverview = (oldStateIsNormal && stateIsOverview);                             
2226         boolean overviewToWorkspace = (oldStateIsOverview && stateIsNormal);                             
2227                                                                                                          
2228         mNewScale = 1.0f;                                                                                
2229                                                                                                          
2230         if (oldStateIsOverview) {                                                                        
2231             disableFreeScroll();                                                                         
2232         } else if (stateIsOverview) {                                                                    
2233             enableFreeScroll();                                                                          
2234         }                                                                                                
2235                                                                                                          
2236         if (state != State.NORMAL) {                                                                     
2237             if (stateIsSpringLoaded) {                                                                   
2238                 mNewScale = mSpringLoadedShrinkFactor;                                                   
2239             } else if (stateIsOverview || stateIsOverviewHidden) {                                       
2240                 mNewScale = mOverviewModeShrinkFactor;                                                   
2241             }                                                                                            
2242         }                                                                                                
2243                                                                                                          
2244         final int duration;                                                                              
2245         if (workspaceToAllApps || overviewToAllApps) {                                                   
2246             duration = HIDE_WORKSPACE_DURATION; //getResources().getInteger(R.integer.config_workspaceUns🔵
2247         } else if (workspaceToOverview || overviewToWorkspace) {                                         
2248             duration = getResources().getInteger(R.integer.config_overviewTransitionTime);               
2249         } else {                                                                                         
2250             duration = getResources().getInteger(R.integer.config_appsCustomizeWorkspaceShrinkTime);     
2251         }                                                                                                
2252                                                                                                          
2253         if (snapPage == -1) {                                                                            
2254             snapPage = getPageNearestToCenterOfScreen();                                                 
2255         }                                                                                                
2256         snapToPage(snapPage, duration, mZoomInInterpolator);                                             
2257                                                                                                          
2258         for (int i = 0; i < getChildCount(); i++) {                                                      
2259             final CellLayout cl = (CellLayout) getChildAt(i);                                            
2260             boolean isCurrentPage = (i == snapPage);                                                     
2261             float initialAlpha = cl.getShortcutsAndWidgets().getAlpha();                                 
2262             float finalAlpha;                                                                            
2263             if (stateIsNormalHidden || stateIsOverviewHidden) {                                          
2264                 finalAlpha = 0f;                                                                         
2265             } else if (stateIsNormal && mWorkspaceFadeInAdjacentScreens) {                               
2266                 finalAlpha = (i == snapPage || i < numCustomPages()) ? 1f : 0f;                          
2267             } else {                                                                                     
2268                 finalAlpha = 1f;                                                                         
2269             }                                                                                            
2270                                                                                                          
2271             // If we are animating to/from the small state, then hide the side pages and fade the        
2272             // current page in                                                                           
2273             if (!mIsSwitchingState) {                                                                    
2274                 if (workspaceToAllApps || allAppsToWorkspace) {                                          
2275                     if (allAppsToWorkspace && isCurrentPage) {                                           
2276                         initialAlpha = 0f;                                                               
2277                     } else if (!isCurrentPage) {                                                         
2278                         initialAlpha = finalAlpha = 0f;                                                  
2279                     }                                                                                    
2280                     cl.setShortcutAndWidgetAlpha(initialAlpha);                                          
2281                 }                                                                                        
2282             }                                                                                            
2283                                                                                                          
2284             mOldAlphas[i] = initialAlpha;                                                                
2285             mNewAlphas[i] = finalAlpha;                                                                  
2286             if (animated) {                                                                              
2287                 mOldBackgroundAlphas[i] = cl.getBackgroundAlpha();                                       
2288                 mNewBackgroundAlphas[i] = finalBackgroundAlpha;                                          
2289             } else {                                                                                     
2290                 cl.setBackgroundAlpha(finalBackgroundAlpha);                                             
2291                 cl.setShortcutAndWidgetAlpha(finalAlpha);                                                
2292             }                                                                                            
2293         }                                                                                                
2294                                                                                                          
2295         final View searchBar = mLauncher.getQsbBar();                                                    
2296         final View overviewPanel = mLauncher.getOverviewPanel();                                         
2297         final View hotseat = mLauncher.getHotseat();                                                     
2298         final View pageIndicator = getPageIndicator();                                                   
2299         if (animated) {                                                                                  
2300             LauncherViewPropertyAnimator scale = new LauncherViewPropertyAnimator(this);                 
2301             scale.scaleX(mNewScale)                                                                      
2302                 .scaleY(mNewScale)                                                                       
2303                 .translationY(finalWorkspaceTranslationY)                                                
2304                 .setDuration(duration)                                                                   
2305                 .setInterpolator(mZoomInInterpolator);                                                   
2306             anim.play(scale);                                                                            
2307             for (int index = 0; index < getChildCount(); index++) {                                      
2308                 final int i = index;                                                                     
2309                 final CellLayout cl = (CellLayout) getChildAt(i);                                        
2310                 float currentAlpha = cl.getShortcutsAndWidgets().getAlpha();                             
2311                 if (mOldAlphas[i] == 0 && mNewAlphas[i] == 0) {                                          
2312                     cl.setBackgroundAlpha(mNewBackgroundAlphas[i]);                                      
2313                     cl.setShortcutAndWidgetAlpha(mNewAlphas[i]);                                         
2314                 } else {                                                                                 
2315                     if (layerViews != null) {                                                            
2316                         layerViews.add(cl);                                                              
2317                     }                                                                                    
2318                     if (mOldAlphas[i] != mNewAlphas[i] || currentAlpha != mNewAlphas[i]) {               
2319                         LauncherViewPropertyAnimator alphaAnim =                                         
2320                             new LauncherViewPropertyAnimator(cl.getShortcutsAndWidgets());               
2321                         alphaAnim.alpha(mNewAlphas[i])                                                   
2322                             .setDuration(duration)                                                       
2323                             .setInterpolator(mZoomInInterpolator);                                       
2324                         anim.play(alphaAnim);                                                            
2325                     }                                                                                    
2326                     if (mOldBackgroundAlphas[i] != 0 ||                                                  
2327                         mNewBackgroundAlphas[i] != 0) {                                                  
2328                         ValueAnimator bgAnim =                                                           
2329                                 LauncherAnimUtils.ofFloat(cl, 0f, 1f);                                   
2330                         bgAnim.setInterpolator(mZoomInInterpolator);                                     
2331                         bgAnim.setDuration(duration);                                                    
2332                         bgAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {                  
2333                                 public void onAnimationUpdate(float a, float b) {                        
2334                                     cl.setBackgroundAlpha(                                               
2335                                             a * mOldBackgroundAlphas[i] +                                
2336                                             b * mNewBackgroundAlphas[i]);                                
2337                                 }                                                                        
2338                             });                                                                          
2339                         anim.play(bgAnim);                                                               
2340                     }                                                                                    
2341                 }                                                                                        
2342             }                                                                                            
2343             Animator pageIndicatorAlpha = null;                                                          
2344             if (pageIndicator != null) {                                                                 
2345                 pageIndicatorAlpha = new LauncherViewPropertyAnimator(pageIndicator)                     
2346                     .alpha(finalHotseatAndPageIndicatorAlpha).withLayer();                               
2347                 pageIndicatorAlpha.addListener(new AlphaUpdateListener(pageIndicator));                  
2348             } else {                                                                                     
2349                 // create a dummy animation so we don't need to do null checks later                     
2350                 pageIndicatorAlpha = ValueAnimator.ofFloat(0, 0);                                        
2351             }                                                                                            
2352                                                                                                          
2353             Animator hotseatAlpha = new LauncherViewPropertyAnimator(hotseat)                            
2354                 .alpha(finalHotseatAndPageIndicatorAlpha).withLayer();                                   
2355             hotseatAlpha.addListener(new AlphaUpdateListener(hotseat));                                  
2356                                                                                                          
2357             Animator searchBarAlpha = new LauncherViewPropertyAnimator(searchBar)                        
2358                 .alpha(finalSearchBarAlpha).withLayer();                                                 
2359             searchBarAlpha.addListener(new AlphaUpdateListener(searchBar));                              
2360                                                                                                          
2361             Animator overviewPanelAlpha = new LauncherViewPropertyAnimator(overviewPanel)                
2362                 .alpha(finalOverviewPanelAlpha).withLayer();                                             
2363             overviewPanelAlpha.addListener(new AlphaUpdateListener(overviewPanel));                      
2364                                                                                                          
2365             // For animation optimations, we may need to provide the Launcher transition                 
2366             // with a set of views on which to force build layers in certain scenarios.                  
2367             hotseat.setLayerType(View.LAYER_TYPE_HARDWARE, null);                                        
2368             searchBar.setLayerType(View.LAYER_TYPE_HARDWARE, null);                                      
2369             overviewPanel.setLayerType(View.LAYER_TYPE_HARDWARE, null);                                  
2370             if (layerViews != null) {                                                                    
2371                 layerViews.add(hotseat);                                                                 
2372                 layerViews.add(searchBar);                                                               
2373                 layerViews.add(overviewPanel);                                                           
2374             }                                                                                            
2375                                                                                                          
2376             if (workspaceToOverview) {                                                                   
2377                 pageIndicatorAlpha.setInterpolator(new DecelerateInterpolator(2));                       
2378                 hotseatAlpha.setInterpolator(new DecelerateInterpolator(2));                             
2379                 overviewPanelAlpha.setInterpolator(null);                                                
2380             } else if (overviewToWorkspace) {                                                            
2381                 pageIndicatorAlpha.setInterpolator(null);                                                
2382                 hotseatAlpha.setInterpolator(null);                                                      
2383                 overviewPanelAlpha.setInterpolator(new DecelerateInterpolator(2));                       
2384             }                                                                                            
2385                                                                                                          
2386             overviewPanelAlpha.setDuration(duration);                                                    
2387             pageIndicatorAlpha.setDuration(duration);                                                    
2388             hotseatAlpha.setDuration(duration);                                                          
2389             searchBarAlpha.setDuration(duration);                                                        
2390                                                                                                          
2391             anim.play(overviewPanelAlpha);                                                               
2392             anim.play(hotseatAlpha);                                                                     
2393             anim.play(searchBarAlpha);                                                                   
2394             anim.play(pageIndicatorAlpha);                                                               
2395             anim.setStartDelay(delay);                                                                   
2396         } else {                                                                                         
2397             overviewPanel.setAlpha(finalOverviewPanelAlpha);                                             
2398             AlphaUpdateListener.updateVisibility(overviewPanel);                                         
2399             hotseat.setAlpha(finalHotseatAndPageIndicatorAlpha);                                         
2400             AlphaUpdateListener.updateVisibility(hotseat);                                               
2401             if (pageIndicator != null) {                                                                 
2402                 pageIndicator.setAlpha(finalHotseatAndPageIndicatorAlpha);                               
2403                 AlphaUpdateListener.updateVisibility(pageIndicator);                                     
2404             }                                                                                            
2405             searchBar.setAlpha(finalSearchBarAlpha);                                                     
2406             AlphaUpdateListener.updateVisibility(searchBar);                                             
2407             updateCustomContentVisibility();                                                             
2408             setScaleX(mNewScale);                                                                        
2409             setScaleY(mNewScale);                                                                        
2410             setTranslationY(finalWorkspaceTranslationY);                                                 
2411         }                                                                                                
2412         mLauncher.updateVoiceButtonProxyVisible(false);                                                  
2413                                                                                                          
2414         if (stateIsNormal) {                                                                             
2415             animateBackgroundGradient(0f, animated);                                                     
2416         } else {                                                                                         
2417             animateBackgroundGradient(getResources().getInteger(                                         
2418                     R.integer.config_workspaceScrimAlpha) / 100f, animated);                             
2419         }                                                                                                
2420         return anim;                                                                                     
2421     }                                                                                                    
2422                                                                                                          
2423     static class AlphaUpdateListener implements AnimatorUpdateListener, AnimatorListener {               
2424         View view;                                                                                       
2425         public AlphaUpdateListener(View v) {                                                             
2426             view = v;                                                                                    
2427         }                                                                                                
2428                                                                                                          
2429         @Override                                                                                        
2430         public void onAnimationUpdate(ValueAnimator arg0) {                                              
2431             updateVisibility(view);                                                                      
2432         }                                                                                                
2433                                                                                                          
2434         public static void updateVisibility(View view) {                                                 
2435             // We want to avoid the extra layout pass by setting the views to GONE unless                
2436             // accessibility is on, in which case not setting them to GONE causes a glitch.              
2437             int invisibleState = sAccessibilityEnabled ? GONE : INVISIBLE;                               
2438             if (view.getAlpha() < ALPHA_CUTOFF_THRESHOLD && view.getVisibility() != invisibleState) {    
2439                 view.setVisibility(invisibleState);                                                      
2440             } else if (view.getAlpha() > ALPHA_CUTOFF_THRESHOLD                                          
2441                     && view.getVisibility() != VISIBLE) {                                                
2442                 view.setVisibility(VISIBLE);                                                             
2443             }                                                                                            
2444         }                                                                                                
2445                                                                                                          
2446         @Override                                                                                        
2447         public void onAnimationCancel(Animator arg0) {                                                   
2448         }                                                                                                
2449                                                                                                          
2450         @Override                                                                                        
2451         public void onAnimationEnd(Animator arg0) {                                                      
2452             updateVisibility(view);                                                                      
2453         }                                                                                                
2454                                                                                                          
2455         @Override                                                                                        
2456         public void onAnimationRepeat(Animator arg0) {                                                   
2457         }                                                                                                
2458                                                                                                          
2459         @Override                                                                                        
2460         public void onAnimationStart(Animator arg0) {                                                    
2461             // We want the views to be visible for animation, so fade-in/out is visible                  
2462             view.setVisibility(VISIBLE);                                                                 
2463         }                                                                                                
2464     }                                                                                                    
2465                                                                                                          
2466     @Override                                                                                            
2467     public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) {         
2468         onTransitionPrepare();                                                                           
2469     }                                                                                                    
2470                                                                                                          
2471     @Override                                                                                            
2472     public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) {           
2473     }                                                                                                    
2474                                                                                                          
2475     @Override                                                                                            
2476     public void onLauncherTransitionStep(Launcher l, float t) {                                          
2477         mTransitionProgress = t;                                                                         
2478     }                                                                                                    
2479                                                                                                          
2480     @Override                                                                                            
2481     public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {             
2482         onTransitionEnd();                                                                               
2483     }                                                                                                    
2484                                                                                                          
2485     private void onTransitionPrepare() {                                                                 
2486         mIsSwitchingState = true;                                                                        
2487                                                                                                          
2488         // Invalidate here to ensure that the pages are rendered during the state change transition.     
2489         invalidate();                                                                                    
2490                                                                                                          
2491         updateChildrenLayersEnabled(false);                                                              
2492         hideCustomContentIfNecessary();                                                                  
2493     }                                                                                                    
2494                                                                                                          
2495     void updateCustomContentVisibility() {                                                               
2496         int visibility = mState == Workspace.State.NORMAL ? VISIBLE : INVISIBLE;                         
2497         if (hasCustomContent()) {                                                                        
2498             mWorkspaceScreens.get(CUSTOM_CONTENT_SCREEN_ID).setVisibility(visibility);                   
2499         }                                                                                                
2500     }                                                                                                    
2501                                                                                                          
2502     void showCustomContentIfNecessary() {                                                                
2503         boolean show  = mState == Workspace.State.NORMAL;                                                
2504         if (show && hasCustomContent()) {                                                                
2505             mWorkspaceScreens.get(CUSTOM_CONTENT_SCREEN_ID).setVisibility(VISIBLE);                      
2506         }                                                                                                
2507     }                                                                                                    
2508                                                                                                          
2509     void hideCustomContentIfNecessary() {                                                                
2510         boolean hide  = mState != Workspace.State.NORMAL;                                                
2511         if (hide && hasCustomContent()) {                                                                
2512             disableLayoutTransitions();                                                                  
2513             mWorkspaceScreens.get(CUSTOM_CONTENT_SCREEN_ID).setVisibility(INVISIBLE);                    
2514             enableLayoutTransitions();                                                                   
2515         }                                                                                                
2516     }                                                                                                    
2517                                                                                                          
2518     private void onTransitionEnd() {                                                                     
2519         mIsSwitchingState = false;                                                                       
2520         updateChildrenLayersEnabled(false);                                                              
2521         showCustomContentIfNecessary();                                                                  
2522     }                                                                                                    
2523                                                                                                          
2524     @Override                                                                                            
2525     public View getContent() {                                                                           
2526         return this;                                                                                     
2527     }                                                                                                    
2528                                                                                                          
2529     /**                                                                                                  
2530      * Draw the View v into the given Canvas.                                                            
2531      *                                                                                                   
2532      * @param v the view to draw                                                                         
2533      * @param destCanvas the canvas to draw on                                                           
2534      * @param padding the horizontal and vertical padding to use when drawing                            
2535      */                                                                                                  
2536     private static void drawDragView(View v, Canvas destCanvas, int padding) {                           
2537         final Rect clipRect = sTempRect;                                                                 
2538         v.getDrawingRect(clipRect);                                                                      
2539                                                                                                          
2540         boolean textVisible = false;                                                                     
2541                                                                                                          
2542         destCanvas.save();                                                                               
2543         if (v instanceof TextView) {                                                                     
2544             Drawable d = ((TextView) v).getCompoundDrawables()[1];                                       
2545             Rect bounds = getDrawableBounds(d);                                                          
2546             clipRect.set(0, 0, bounds.width() + padding, bounds.height() + padding);                     
2547             destCanvas.translate(padding / 2 - bounds.left, padding / 2 - bounds.top);                   
2548             d.draw(destCanvas);                                                                          
2549         } else {                                                                                         
2550             if (v instanceof FolderIcon) {                                                               
2551                 // For FolderIcons the text can bleed into the icon area, and so we need to              
2552                 // hide the text completely (which can't be achieved by clipping).                       
2553                 if (((FolderIcon) v).getTextVisible()) {                                                 
2554                     ((FolderIcon) v).setTextVisible(false);                                              
2555                     textVisible = true;                                                                  
2556                 }                                                                                        
2557             }                                                                                            
2558             destCanvas.translate(-v.getScrollX() + padding / 2, -v.getScrollY() + padding / 2);          
2559             destCanvas.clipRect(clipRect, Op.REPLACE);                                                   
2560             v.draw(destCanvas);                                                                          
2561                                                                                                          
2562             // Restore text visibility of FolderIcon if necessary                                        
2563             if (textVisible) {                                                                           
2564                 ((FolderIcon) v).setTextVisible(true);                                                   
2565             }                                                                                            
2566         }                                                                                                
2567         destCanvas.restore();                                                                            
2568     }                                                                                                    
2569                                                                                                          
2570     /**                                                                                                  
2571      * Returns a new bitmap to show when the given View is being dragged around.                         
2572      * Responsibility for the bitmap is transferred to the caller.                                       
2573      * @param expectedPadding padding to add to the drag view. If a different padding was used           
2574      * its value will be changed                                                                         
2575      */                                                                                                  
2576     public Bitmap createDragBitmap(View v, AtomicInteger expectedPadding) {                              
2577         Bitmap b;                                                                                        
2578                                                                                                          
2579         int padding = expectedPadding.get();                                                             
2580         if (v instanceof TextView) {                                                                     
2581             Drawable d = ((TextView) v).getCompoundDrawables()[1];                                       
2582             Rect bounds = getDrawableBounds(d);                                                          
2583             b = Bitmap.createBitmap(bounds.width() + padding,                                            
2584                     bounds.height() + padding, Bitmap.Config.ARGB_8888);                                 
2585             expectedPadding.set(padding - bounds.left - bounds.top);                                     
2586         } else {                                                                                         
2587             b = Bitmap.createBitmap(                                                                     
2588                     v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);           
2589         }                                                                                                
2590                                                                                                          
2591         mCanvas.setBitmap(b);                                                                            
2592         drawDragView(v, mCanvas, padding);                                                               
2593         mCanvas.setBitmap(null);                                                                         
2594                                                                                                          
2595         return b;                                                                                        
2596     }                                                                                                    
2597                                                                                                          
2598     /**                                                                                                  
2599      * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.       
2600      * Responsibility for the bitmap is transferred to the caller.                                       
2601      */                                                                                                  
2602     private Bitmap createDragOutline(View v, int padding) {                                              
2603         final int outlineColor = getResources().getColor(R.color.outline_color);                         
2604         final Bitmap b = Bitmap.createBitmap(                                                            
2605                 v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);               
2606                                                                                                          
2607         mCanvas.setBitmap(b);                                                                            
2608         drawDragView(v, mCanvas, padding);                                                               
2609         mOutlineHelper.applyExpensiveOutlineWithBlur(b, mCanvas, outlineColor, outlineColor);            
2610         mCanvas.setBitmap(null);                                                                         
2611         return b;                                                                                        
2612     }                                                                                                    
2613                                                                                                          
2614     /**                                                                                                  
2615      * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.       
2616      * Responsibility for the bitmap is transferred to the caller.                                       
2617      */                                                                                                  
2618     private Bitmap createDragOutline(Bitmap orig, int padding, int w, int h,                             
2619             boolean clipAlpha) {                                                                         
2620         final int outlineColor = getResources().getColor(R.color.outline_color);                         
2621         final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);                             
2622         mCanvas.setBitmap(b);                                                                            
2623                                                                                                          
2624         Rect src = new Rect(0, 0, orig.getWidth(), orig.getHeight());                                    
2625         float scaleFactor = Math.min((w - padding) / (float) orig.getWidth(),                            
2626                 (h - padding) / (float) orig.getHeight());                                               
2627         int scaledWidth = (int) (scaleFactor * orig.getWidth());                                         
2628         int scaledHeight = (int) (scaleFactor * orig.getHeight());                                       
2629         Rect dst = new Rect(0, 0, scaledWidth, scaledHeight);                                            
2630                                                                                                          
2631         // center the image                                                                              
2632         dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2);                                       
2633                                                                                                          
2634         mCanvas.drawBitmap(orig, src, dst, null);                                                        
2635         mOutlineHelper.applyExpensiveOutlineWithBlur(b, mCanvas, outlineColor, outlineColor,             
2636                 clipAlpha);                                                                              
2637         mCanvas.setBitmap(null);                                                                         
2638                                                                                                          
2639         return b;                                                                                        
2640     }                                                                                                    
2641                                                                                                          
2642     void startDrag(CellLayout.CellInfo cellInfo) {                                                       
2643         View child = cellInfo.cell;                                                                      
2644                                                                                                          
2645         // Make sure the drag was started by a long press as opposed to a long click.                    
2646         if (!child.isInTouchMode()) {                                                                    
2647             return;                                                                                      
2648         }                                                                                                
2649                                                                                                          
2650         mDragInfo = cellInfo;                                                                            
2651         child.setVisibility(INVISIBLE);                                                                  
2652         CellLayout layout = (CellLayout) child.getParent().getParent();                                  
2653         layout.prepareChildForDrag(child);                                                               
2654                                                                                                          
2655         beginDragShared(child, this);                                                                    
2656     }                                                                                                    
2657                                                                                                          
2658     public void beginDragShared(View child, DragSource source) {                                         
2659         child.clearFocus();                                                                              
2660         child.setPressed(false);                                                                         
2661                                                                                                          
2662         // The outline is used to visualize where the item will land if dropped                          
2663         mDragOutline = createDragOutline(child, DRAG_BITMAP_PADDING);                                    
2664                                                                                                          
2665         mLauncher.onDragStarted(child);                                                                  
2666         // The drag bitmap follows the touch point around on the screen                                  
2667         AtomicInteger padding = new AtomicInteger(DRAG_BITMAP_PADDING);                                  
2668         final Bitmap b = createDragBitmap(child, padding);                                               
2669                                                                                                          
2670         final int bmpWidth = b.getWidth();                                                               
2671         final int bmpHeight = b.getHeight();                                                             
2672                                                                                                          
2673         float scale = mLauncher.getDragLayer().getLocationInDragLayer(child, mTempXY);                   
2674         int dragLayerX = Math.round(mTempXY[0] - (bmpWidth - scale * child.getWidth()) / 2);             
2675         int dragLayerY = Math.round(mTempXY[1] - (bmpHeight - scale * bmpHeight) / 2                     
2676                         - padding.get() / 2);                                                            
2677                                                                                                          
2678         LauncherAppState app = LauncherAppState.getInstance();                                           
2679         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                    
2680         Point dragVisualizeOffset = null;                                                                
2681         Rect dragRect = null;                                                                            
2682         if (child instanceof BubbleTextView) {                                                           
2683             int iconSize = grid.iconSizePx;                                                              
2684             int top = child.getPaddingTop();                                                             
2685             int left = (bmpWidth - iconSize) / 2;                                                        
2686             int right = left + iconSize;                                                                 
2687             int bottom = top + iconSize;                                                                 
2688             dragLayerY += top;                                                                           
2689             // Note: The drag region is used to calculate drag layer offsets, but the                    
2690             // dragVisualizeOffset in addition to the dragRect (the size) to position the outline.       
2691             dragVisualizeOffset = new Point(-padding.get() / 2, padding.get() / 2);                      
2692             dragRect = new Rect(left, top, right, bottom);                                               
2693         } else if (child instanceof FolderIcon) {                                                        
2694             int previewSize = grid.folderIconSizePx;                                                     
2695             dragRect = new Rect(0, child.getPaddingTop(), child.getWidth(), previewSize);                
2696         }                                                                                                
2697                                                                                                          
2698         // Clear the pressed state if necessary                                                          
2699         if (child instanceof BubbleTextView) {                                                           
2700             BubbleTextView icon = (BubbleTextView) child;                                                
2701             icon.clearPressedBackground();                                                               
2702         }                                                                                                
2703                                                                                                          
2704         if (child.getTag() == null || !(child.getTag() instanceof ItemInfo)) {                           
2705             String msg = "Drag started with a view that has no tag set. This "                           
2706                     + "will cause a crash (issue 11627249) down the line. "                              
2707                     + "View: " + child + "  tag: " + child.getTag();                                     
2708             throw new IllegalStateException(msg);                                                        
2709         }                                                                                                
2710                                                                                                          
2711         DragView dv = mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(),       
2712                 DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, scale);                  
2713         dv.setIntrinsicIconScaleFactor(source.getIntrinsicIconScaleFactor());                            
2714                                                                                                          
2715         if (child.getParent() instanceof ShortcutAndWidgetContainer) {                                   
2716             mDragSourceInternal = (ShortcutAndWidgetContainer) child.getParent();                        
2717         }                                                                                                
2718                                                                                                          
2719         b.recycle();                                                                                     
2720     }                                                                                                    
2721                                                                                                          
2722     public void beginExternalDragShared(View child, DragSource source) {                                 
2723         LauncherAppState app = LauncherAppState.getInstance();                                           
2724         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                    
2725         int iconSize = grid.iconSizePx;                                                                  
2726                                                                                                          
2727         // Notify launcher of drag start                                                                 
2728         mLauncher.onDragStarted(child);                                                                  
2729                                                                                                          
2730         // Compose a new drag bitmap that is of the icon size                                            
2731         AtomicInteger padding = new AtomicInteger(DRAG_BITMAP_PADDING);                                  
2732         final Bitmap tmpB = createDragBitmap(child, padding);                                            
2733         Bitmap b = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);                     
2734         Paint p = new Paint();                                                                           
2735         p.setFilterBitmap(true);                                                                         
2736         mCanvas.setBitmap(b);                                                                            
2737         mCanvas.drawBitmap(tmpB, new Rect(0, 0, tmpB.getWidth(), tmpB.getHeight()),                      
2738                 new Rect(0, 0, iconSize, iconSize), p);                                                  
2739         mCanvas.setBitmap(null);                                                                         
2740                                                                                                          
2741         // Find the child's location on the screen                                                       
2742         int bmpWidth = tmpB.getWidth();                                                                  
2743         float iconScale = (float) bmpWidth / iconSize;                                                   
2744         float scale = mLauncher.getDragLayer().getLocationInDragLayer(child, mTempXY) * iconScale;       
2745         int dragLayerX = Math.round(mTempXY[0] - (bmpWidth - scale * child.getWidth()) / 2);             
2746         int dragLayerY = Math.round(mTempXY[1]);                                                         
2747                                                                                                          
2748         // Note: The drag region is used to calculate drag layer offsets, but the                        
2749         // dragVisualizeOffset in addition to the dragRect (the size) to position the outline.           
2750         Point dragVisualizeOffset = new Point(-padding.get() / 2, padding.get() / 2);                    
2751         Rect dragRect = new Rect(0, 0, iconSize, iconSize);                                              
2752                                                                                                          
2753         if (child.getTag() == null || !(child.getTag() instanceof ItemInfo)) {                           
2754             String msg = "Drag started with a view that has no tag set. This "                           
2755                     + "will cause a crash (issue 11627249) down the line. "                              
2756                     + "View: " + child + "  tag: " + child.getTag();                                     
2757             throw new IllegalStateException(msg);                                                        
2758         }                                                                                                
2759                                                                                                          
2760         // Start the drag                                                                                
2761         DragView dv = mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(),       
2762                 DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, scale);                  
2763         dv.setIntrinsicIconScaleFactor(source.getIntrinsicIconScaleFactor());                            
2764                                                                                                          
2765         // Recycle temporary bitmaps                                                                     
2766         tmpB.recycle();                                                                                  
2767     }                                                                                                    
2768                                                                                                          
2769     void addApplicationShortcut(ShortcutInfo info, CellLayout target, long container, long screenId,     
2770             int cellX, int cellY, boolean insertAtFirst, int intersectX, int intersectY) {               
2771         View view = mLauncher.createShortcut(R.layout.application, target, (ShortcutInfo) info);         
2772                                                                                                          
2773         final int[] cellXY = new int[2];                                                                 
2774         target.findCellForSpanThatIntersects(cellXY, 1, 1, intersectX, intersectY);                      
2775         addInScreen(view, container, screenId, cellXY[0], cellXY[1], 1, 1, insertAtFirst);               
2776                                                                                                          
2777         LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screenId, cellXY[0],           
2778                 cellXY[1]);                                                                              
2779     }                                                                                                    
2780                                                                                                          
2781     public boolean transitionStateShouldAllowDrop() {                                                    
2782         return ((!isSwitchingState() || mTransitionProgress > 0.5f) &&                                   
2783                 (mState == State.NORMAL || mState == State.SPRING_LOADED));                              
2784     }                                                                                                    
2785                                                                                                          
2786     /**                                                                                                  
2787      * {@inheritDoc}                                                                                     
2788      */                                                                                                  
2789     public boolean acceptDrop(DragObject d) {                                                            
2790         // If it's an external drop (e.g. from All Apps), check if it should be accepted                 
2791         CellLayout dropTargetLayout = mDropToLayout;                                                     
2792         if (d.dragSource != this) {                                                                      
2793             // Don't accept the drop if we're not over a screen at time of drop                          
2794             if (dropTargetLayout == null) {                                                              
2795                 return false;                                                                            
2796             }                                                                                            
2797             if (!transitionStateShouldAllowDrop()) return false;                                         
2798                                                                                                          
2799             mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset,              
2800                     d.dragView, mDragViewVisualCenter);                                                  
2801                                                                                                          
2802             // We want the point to be mapped to the dragTarget.                                         
2803             if (mLauncher.isHotseatLayout(dropTargetLayout)) {                                           
2804                 mapPointFromSelfToHotseatLayout(mLauncher.getHotseat(), mDragViewVisualCenter);          
2805             } else {                                                                                     
2806                 mapPointFromSelfToChild(dropTargetLayout, mDragViewVisualCenter, null);                  
2807             }                                                                                            
2808                                                                                                          
2809             int spanX = 1;                                                                               
2810             int spanY = 1;                                                                               
2811             if (mDragInfo != null) {                                                                     
2812                 final CellLayout.CellInfo dragCellInfo = mDragInfo;                                      
2813                 spanX = dragCellInfo.spanX;                                                              
2814                 spanY = dragCellInfo.spanY;                                                              
2815             } else {                                                                                     
2816                 final ItemInfo dragInfo = (ItemInfo) d.dragInfo;                                         
2817                 spanX = dragInfo.spanX;                                                                  
2818                 spanY = dragInfo.spanY;                                                                  
2819             }                                                                                            
2820                                                                                                          
2821             int minSpanX = spanX;                                                                        
2822             int minSpanY = spanY;                                                                        
2823             if (d.dragInfo instanceof PendingAddWidgetInfo) {                                            
2824                 minSpanX = ((PendingAddWidgetInfo) d.dragInfo).minSpanX;                                 
2825                 minSpanY = ((PendingAddWidgetInfo) d.dragInfo).minSpanY;                                 
2826             }                                                                                            
2827                                                                                                          
2828             mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],                                
2829                     (int) mDragViewVisualCenter[1], minSpanX, minSpanY, dropTargetLayout,                
2830                     mTargetCell);                                                                        
2831             float distance = dropTargetLayout.getDistanceFromCell(mDragViewVisualCenter[0],              
2832                     mDragViewVisualCenter[1], mTargetCell);                                              
2833             if (willCreateUserFolder((ItemInfo) d.dragInfo, dropTargetLayout,                            
2834                     mTargetCell, distance, true)) {                                                      
2835                 return true;                                                                             
2836             }                                                                                            
2837             if (willAddToExistingUserFolder((ItemInfo) d.dragInfo, dropTargetLayout,                     
2838                     mTargetCell, distance)) {                                                            
2839                 return true;                                                                             
2840             }                                                                                            
2841                                                                                                          
2842             int[] resultSpan = new int[2];                                                               
2843             mTargetCell = dropTargetLayout.performReorder((int) mDragViewVisualCenter[0],                
2844                     (int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY,                    
2845                     null, mTargetCell, resultSpan, CellLayout.MODE_ACCEPT_DROP);                         
2846             boolean foundCell = mTargetCell[0] >= 0 && mTargetCell[1] >= 0;                              
2847                                                                                                          
2848             // Don't accept the drop if there's no room for the item                                     
2849             if (!foundCell) {                                                                            
2850                 // Don't show the message if we are dropping on the AllApps button and the hotseat       
2851                 // is full                                                                               
2852                 boolean isHotseat = mLauncher.isHotseatLayout(dropTargetLayout);                         
2853                 if (mTargetCell != null && isHotseat) {                                                  
2854                     Hotseat hotseat = mLauncher.getHotseat();                                            
2855                     if (hotseat.isAllAppsButtonRank(                                                     
2856                             hotseat.getOrderInHotseat(mTargetCell[0], mTargetCell[1]))) {                
2857                         return false;                                                                    
2858                     }                                                                                    
2859                 }                                                                                        
2860                                                                                                          
2861                 mLauncher.showOutOfSpaceMessage(isHotseat);                                              
2862                 return false;                                                                            
2863             }                                                                                            
2864         }                                                                                                
2865                                                                                                          
2866         long screenId = getIdForScreen(dropTargetLayout);                                                
2867         if (screenId == EXTRA_EMPTY_SCREEN_ID) {                                                         
2868             commitExtraEmptyScreen();                                                                    
2869         }                                                                                                
2870                                                                                                          
2871         return true;                                                                                     
2872     }                                                                                                    
2873                                                                                                          
2874     boolean willCreateUserFolder(ItemInfo info, CellLayout target, int[] targetCell, float               
2875             distance, boolean considerTimeout) {                                                         
2876         if (distance > mMaxDistanceForFolderCreation) return false;                                      
2877         View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);                             
2878                                                                                                          
2879         if (dropOverView != null) {                                                                      
2880             CellLayout.LayoutParams lp = (CellLayout.LayoutParams) dropOverView.getLayoutParams();       
2881             if (lp.useTmpCoords && (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.tmpCellY)) {            
2882                 return false;                                                                            
2883             }                                                                                            
2884         }                                                                                                
2885                                                                                                          
2886         boolean hasntMoved = false;                                                                      
2887         if (mDragInfo != null) {                                                                         
2888             hasntMoved = dropOverView == mDragInfo.cell;                                                 
2889         }                                                                                                
2890                                                                                                          
2891         if (dropOverView == null || hasntMoved || (considerTimeout && !mCreateUserFolderOnDrop)) {       
2892             return false;                                                                                
2893         }                                                                                                
2894                                                                                                          
2895         boolean aboveShortcut = (dropOverView.getTag() instanceof ShortcutInfo);                         
2896         boolean willBecomeShortcut =                                                                     
2897                 (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||                    
2898                 info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT);                         
2899                                                                                                          
2900         return (aboveShortcut && willBecomeShortcut);                                                    
2901     }                                                                                                    
2902                                                                                                          
2903     boolean willAddToExistingUserFolder(Object dragInfo, CellLayout target, int[] targetCell,            
2904             float distance) {                                                                            
2905         if (distance > mMaxDistanceForFolderCreation) return false;                                      
2906         View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);                             
2907                                                                                                          
2908         if (dropOverView != null) {                                                                      
2909             CellLayout.LayoutParams lp = (CellLayout.LayoutParams) dropOverView.getLayoutParams();       
2910             if (lp.useTmpCoords && (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.tmpCellY)) {            
2911                 return false;                                                                            
2912             }                                                                                            
2913         }                                                                                                
2914                                                                                                          
2915         if (dropOverView instanceof FolderIcon) {                                                        
2916             FolderIcon fi = (FolderIcon) dropOverView;                                                   
2917             if (fi.acceptDrop(dragInfo)) {                                                               
2918                 return true;                                                                             
2919             }                                                                                            
2920         }                                                                                                
2921         return false;                                                                                    
2922     }                                                                                                    
2923                                                                                                          
2924     boolean createUserFolderIfNecessary(View newView, long container, CellLayout target,                 
2925             int[] targetCell, float distance, boolean external, DragView dragView,                       
2926             Runnable postAnimationRunnable) {                                                            
2927         if (distance > mMaxDistanceForFolderCreation) return false;                                      
2928         View v = target.getChildAt(targetCell[0], targetCell[1]);                                        
2929                                                                                                          
2930         boolean hasntMoved = false;                                                                      
2931         if (mDragInfo != null) {                                                                         
2932             CellLayout cellParent = getParentCellLayoutForView(mDragInfo.cell);                          
2933             hasntMoved = (mDragInfo.cellX == targetCell[0] &&                                            
2934                     mDragInfo.cellY == targetCell[1]) && (cellParent == target);                         
2935         }                                                                                                
2936                                                                                                          
2937         if (v == null || hasntMoved || !mCreateUserFolderOnDrop) return false;                           
2938         mCreateUserFolderOnDrop = false;                                                                 
2939         final long screenId = (targetCell == null) ? mDragInfo.screenId : getIdForScreen(target);        
2940                                                                                                          
2941         boolean aboveShortcut = (v.getTag() instanceof ShortcutInfo);                                    
2942         boolean willBecomeShortcut = (newView.getTag() instanceof ShortcutInfo);                         
2943                                                                                                          
2944         if (aboveShortcut && willBecomeShortcut) {                                                       
2945             ShortcutInfo sourceInfo = (ShortcutInfo) newView.getTag();                                   
2946             ShortcutInfo destInfo = (ShortcutInfo) v.getTag();                                           
2947             // if the drag started here, we need to remove it from the workspace                         
2948             if (!external) {                                                                             
2949                 getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell);                   
2950             }                                                                                            
2951                                                                                                          
2952             Rect folderLocation = new Rect();                                                            
2953             float scale = mLauncher.getDragLayer().getDescendantRectRelativeToSelf(v, folderLocation);   
2954             target.removeView(v);                                                                        
2955                                                                                                          
2956             FolderIcon fi =                                                                              
2957                 mLauncher.addFolder(target, container, screenId, targetCell[0], targetCell[1]);          
2958             destInfo.cellX = -1;                                                                         
2959             destInfo.cellY = -1;                                                                         
2960             sourceInfo.cellX = -1;                                                                       
2961             sourceInfo.cellY = -1;                                                                       
2962                                                                                                          
2963             // If the dragView is null, we can't animate                                                 
2964             boolean animate = dragView != null;                                                          
2965             if (animate) {                                                                               
2966                 fi.performCreateAnimation(destInfo, v, sourceInfo, dragView, folderLocation, scale,      
2967                         postAnimationRunnable);                                                          
2968             } else {                                                                                     
2969                 fi.addItem(destInfo);                                                                    
2970                 fi.addItem(sourceInfo);                                                                  
2971             }                                                                                            
2972             return true;                                                                                 
2973         }                                                                                                
2974         return false;                                                                                    
2975     }                                                                                                    
2976                                                                                                          
2977     boolean addToExistingFolderIfNecessary(View newView, CellLayout target, int[] targetCell,            
2978             float distance, DragObject d, boolean external) {                                            
2979         if (distance > mMaxDistanceForFolderCreation) return false;                                      
2980                                                                                                          
2981         View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);                             
2982         if (!mAddToExistingFolderOnDrop) return false;                                                   
2983         mAddToExistingFolderOnDrop = false;                                                              
2984                                                                                                          
2985         if (dropOverView instanceof FolderIcon) {                                                        
2986             FolderIcon fi = (FolderIcon) dropOverView;                                                   
2987             if (fi.acceptDrop(d.dragInfo)) {                                                             
2988                 fi.onDrop(d);                                                                            
2989                                                                                                          
2990                 // if the drag started here, we need to remove it from the workspace                     
2991                 if (!external) {                                                                         
2992                     getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell);               
2993                 }                                                                                        
2994                 return true;                                                                             
2995             }                                                                                            
2996         }                                                                                                
2997         return false;                                                                                    
2998     }                                                                                                    
2999                                                                                                          
3000     public void onDrop(final DragObject d) {                                                             
3001         mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, d.dragView,      
3002                 mDragViewVisualCenter);                                                                  
3003                                                                                                          
3004         CellLayout dropTargetLayout = mDropToLayout;                                                     
3005                                                                                                          
3006         // We want the point to be mapped to the dragTarget.                                             
3007         if (dropTargetLayout != null) {                                                                  
3008             if (mLauncher.isHotseatLayout(dropTargetLayout)) {                                           
3009                 mapPointFromSelfToHotseatLayout(mLauncher.getHotseat(), mDragViewVisualCenter);          
3010             } else {                                                                                     
3011                 mapPointFromSelfToChild(dropTargetLayout, mDragViewVisualCenter, null);                  
3012             }                                                                                            
3013         }                                                                                                
3014                                                                                                          
3015         int snapScreen = -1;                                                                             
3016         boolean resizeOnDrop = false;                                                                    
3017         if (d.dragSource != this) {                                                                      
3018             final int[] touchXY = new int[] { (int) mDragViewVisualCenter[0],                            
3019                     (int) mDragViewVisualCenter[1] };                                                    
3020             onDropExternal(touchXY, d.dragInfo, dropTargetLayout, false, d);                             
3021         } else if (mDragInfo != null) {                                                                  
3022             final View cell = mDragInfo.cell;                                                            
3023                                                                                                          
3024             Runnable resizeRunnable = null;                                                              
3025             if (dropTargetLayout != null && !d.cancelled) {                                              
3026                 // Move internally                                                                       
3027                 boolean hasMovedLayouts = (getParentCellLayoutForView(cell) != dropTargetLayout);        
3028                 boolean hasMovedIntoHotseat = mLauncher.isHotseatLayout(dropTargetLayout);               
3029                 long container = hasMovedIntoHotseat ?                                                   
3030                         LauncherSettings.Favorites.CONTAINER_HOTSEAT :                                   
3031                         LauncherSettings.Favorites.CONTAINER_DESKTOP;                                    
3032                 long screenId = (mTargetCell[0] < 0) ?                                                   
3033                         mDragInfo.screenId : getIdForScreen(dropTargetLayout);                           
3034                 int spanX = mDragInfo != null ? mDragInfo.spanX : 1;                                     
3035                 int spanY = mDragInfo != null ? mDragInfo.spanY : 1;                                     
3036                 // First we find the cell nearest to point at which the item is                          
3037                 // dropped, without any consideration to whether there is an item there.                 
3038                                                                                                          
3039                 mTargetCell = findNearestArea((int) mDragViewVisualCenter[0], (int)                      
3040                         mDragViewVisualCenter[1], spanX, spanY, dropTargetLayout, mTargetCell);          
3041                 float distance = dropTargetLayout.getDistanceFromCell(mDragViewVisualCenter[0],          
3042                         mDragViewVisualCenter[1], mTargetCell);                                          
3043                                                                                                          
3044                 // If the item being dropped is a shortcut and the nearest drop                          
3045                 // cell also contains a shortcut, then create a folder with the two shortcuts.           
3046                 if (!mInScrollArea && createUserFolderIfNecessary(cell, container,                       
3047                         dropTargetLayout, mTargetCell, distance, false, d.dragView, null)) {             
3048                     return;                                                                              
3049                 }                                                                                        
3050                                                                                                          
3051                 if (addToExistingFolderIfNecessary(cell, dropTargetLayout, mTargetCell,                  
3052                         distance, d, false)) {                                                           
3053                     return;                                                                              
3054                 }                                                                                        
3055                                                                                                          
3056                 // Aside from the special case where we're dropping a shortcut onto a shortcut,          
3057                 // we need to find the nearest cell location that is vacant                              
3058                 ItemInfo item = (ItemInfo) d.dragInfo;                                                   
3059                 int minSpanX = item.spanX;                                                               
3060                 int minSpanY = item.spanY;                                                               
3061                 if (item.minSpanX > 0 && item.minSpanY > 0) {                                            
3062                     minSpanX = item.minSpanX;                                                            
3063                     minSpanY = item.minSpanY;                                                            
3064                 }                                                                                        
3065                                                                                                          
3066                 int[] resultSpan = new int[2];                                                           
3067                 mTargetCell = dropTargetLayout.performReorder((int) mDragViewVisualCenter[0],            
3068                         (int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY, cell,          
3069                         mTargetCell, resultSpan, CellLayout.MODE_ON_DROP);                               
3070                                                                                                          
3071                 boolean foundCell = mTargetCell[0] >= 0 && mTargetCell[1] >= 0;                          
3072                                                                                                          
3073                 // if the widget resizes on drop                                                         
3074                 if (foundCell && (cell instanceof AppWidgetHostView) &&                                  
3075                         (resultSpan[0] != item.spanX || resultSpan[1] != item.spanY)) {                  
3076                     resizeOnDrop = true;                                                                 
3077                     item.spanX = resultSpan[0];                                                          
3078                     item.spanY = resultSpan[1];                                                          
3079                     AppWidgetHostView awhv = (AppWidgetHostView) cell;                                   
3080                     AppWidgetResizeFrame.updateWidgetSizeRanges(awhv, mLauncher, resultSpan[0],          
3081                             resultSpan[1]);                                                              
3082                 }                                                                                        
3083                                                                                                          
3084                 if (getScreenIdForPageIndex(mCurrentPage) != screenId && !hasMovedIntoHotseat) {         
3085                     snapScreen = getPageIndexForScreenId(screenId);                                      
3086                     snapToPage(snapScreen);                                                              
3087                 }                                                                                        
3088                                                                                                          
3089                 if (foundCell) {                                                                         
3090                     final ItemInfo info = (ItemInfo) cell.getTag();                                      
3091                     if (hasMovedLayouts) {                                                               
3092                         // Reparent the view                                                             
3093                         CellLayout parentCell = getParentCellLayoutForView(cell);                        
3094                         if (parentCell != null) {                                                        
3095                             parentCell.removeView(cell);                                                 
3096                         } else if (LauncherAppState.isDogfoodBuild()) {                                  
3097                             throw new NullPointerException("mDragInfo.cell has null parent");            
3098                         }                                                                                
3099                         addInScreen(cell, container, screenId, mTargetCell[0], mTargetCell[1],           
3100                                 info.spanX, info.spanY);                                                 
3101                     }                                                                                    
3102                                                                                                          
3103                     // update the item's position after drop                                             
3104                     CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();       
3105                     lp.cellX = lp.tmpCellX = mTargetCell[0];                                             
3106                     lp.cellY = lp.tmpCellY = mTargetCell[1];                                             
3107                     lp.cellHSpan = item.spanX;                                                           
3108                     lp.cellVSpan = item.spanY;                                                           
3109                     lp.isLockedToGrid = true;                                                            
3110                                                                                                          
3111                     if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT &&                     
3112                             cell instanceof LauncherAppWidgetHostView) {                                 
3113                         final CellLayout cellLayout = dropTargetLayout;                                  
3114                         // We post this call so that the widget has a chance to be placed                
3115                         // in its final location                                                         
3116                                                                                                          
3117                         final LauncherAppWidgetHostView hostView = (LauncherAppWidgetHostView) cell;     
3118                         AppWidgetProviderInfo pinfo = hostView.getAppWidgetInfo();                       
3119                         if (pinfo != null &&                                                             
3120                                 pinfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE) {                 
3121                             final Runnable addResizeFrame = new Runnable() {                             
3122                                 public void run() {                                                      
3123                                     DragLayer dragLayer = mLauncher.getDragLayer();                      
3124                                     dragLayer.addResizeFrame(info, hostView, cellLayout);                
3125                                 }                                                                        
3126                             };                                                                           
3127                             resizeRunnable = (new Runnable() {                                           
3128                                 public void run() {                                                      
3129                                     if (!isPageMoving()) {                                               
3130                                         addResizeFrame.run();                                            
3131                                     } else {                                                             
3132                                         mDelayedResizeRunnable = addResizeFrame;                         
3133                                     }                                                                    
3134                                 }                                                                        
3135                             });                                                                          
3136                         }                                                                                
3137                     }                                                                                    
3138                                                                                                          
3139                     LauncherModel.modifyItemInDatabase(mLauncher, info, container, screenId, lp.cellX,   
3140                             lp.cellY, item.spanX, item.spanY);                                           
3141                 } else {                                                                                 
3142                     // If we can't find a drop location, we return the item to its original position     
3143                     CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();       
3144                     mTargetCell[0] = lp.cellX;                                                           
3145                     mTargetCell[1] = lp.cellY;                                                           
3146                     CellLayout layout = (CellLayout) cell.getParent().getParent();                       
3147                     layout.markCellsAsOccupiedForView(cell);                                             
3148                 }                                                                                        
3149             }                                                                                            
3150                                                                                                          
3151             final CellLayout parent = (CellLayout) cell.getParent().getParent();                         
3152             final Runnable finalResizeRunnable = resizeRunnable;                                         
3153             // Prepare it to be animated into its new position                                           
3154             // This must be called after the view has been re-parented                                   
3155             final Runnable onCompleteRunnable = new Runnable() {                                         
3156                 @Override                                                                                
3157                 public void run() {                                                                      
3158                     mAnimatingViewIntoPlace = false;                                                     
3159                     updateChildrenLayersEnabled(false);                                                  
3160                     if (finalResizeRunnable != null) {                                                   
3161                         finalResizeRunnable.run();                                                       
3162                     }                                                                                    
3163                 }                                                                                        
3164             };                                                                                           
3165             mAnimatingViewIntoPlace = true;                                                              
3166             if (d.dragView.hasDrawn()) {                                                                 
3167                 final ItemInfo info = (ItemInfo) cell.getTag();                                          
3168                 if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET) {                   
3169                     int animationType = resizeOnDrop ? ANIMATE_INTO_POSITION_AND_RESIZE :                
3170                             ANIMATE_INTO_POSITION_AND_DISAPPEAR;                                         
3171                     animateWidgetDrop(info, parent, d.dragView,                                          
3172                             onCompleteRunnable, animationType, cell, false);                             
3173                 } else {                                                                                 
3174                     int duration = snapScreen < 0 ? -1 : ADJACENT_SCREEN_DROP_DURATION;                  
3175                     mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, cell, duration,         
3176                             onCompleteRunnable, this);                                                   
3177                 }                                                                                        
3178             } else {                                                                                     
3179                 d.deferDragViewCleanupPostAnimation = false;                                             
3180                 cell.setVisibility(VISIBLE);                                                             
3181             }                                                                                            
3182             parent.onDropChild(cell);                                                                    
3183         }                                                                                                
3184     }                                                                                                    
3185                                                                                                          
3186     public void setFinalScrollForPageChange(int pageIndex) {                                             
3187         CellLayout cl = (CellLayout) getChildAt(pageIndex);                                              
3188         if (cl != null) {                                                                                
3189             mSavedScrollX = getScrollX();                                                                
3190             mSavedTranslationX = cl.getTranslationX();                                                   
3191             mSavedRotationY = cl.getRotationY();                                                         
3192             final int newX = getScrollForPage(pageIndex);                                                
3193             setScrollX(newX);                                                                            
3194             cl.setTranslationX(0f);                                                                      
3195             cl.setRotationY(0f);                                                                         
3196         }                                                                                                
3197     }                                                                                                    
3198                                                                                                          
3199     public void resetFinalScrollForPageChange(int pageIndex) {                                           
3200         if (pageIndex >= 0) {                                                                            
3201             CellLayout cl = (CellLayout) getChildAt(pageIndex);                                          
3202             setScrollX(mSavedScrollX);                                                                   
3203             cl.setTranslationX(mSavedTranslationX);                                                      
3204             cl.setRotationY(mSavedRotationY);                                                            
3205         }                                                                                                
3206     }                                                                                                    
3207                                                                                                          
3208     public void getViewLocationRelativeToSelf(View v, int[] location) {                                  
3209         getLocationInWindow(location);                                                                   
3210         int x = location[0];                                                                             
3211         int y = location[1];                                                                             
3212                                                                                                          
3213         v.getLocationInWindow(location);                                                                 
3214         int vX = location[0];                                                                            
3215         int vY = location[1];                                                                            
3216                                                                                                          
3217         location[0] = vX - x;                                                                            
3218         location[1] = vY - y;                                                                            
3219     }                                                                                                    
3220                                                                                                          
3221     public void onDragEnter(DragObject d) {                                                              
3222         mDragEnforcer.onDragEnter();                                                                     
3223         mCreateUserFolderOnDrop = false;                                                                 
3224         mAddToExistingFolderOnDrop = false;                                                              
3225                                                                                                          
3226         mDropToLayout = null;                                                                            
3227         CellLayout layout = getCurrentDropLayout();                                                      
3228         setCurrentDropLayout(layout);                                                                    
3229         setCurrentDragOverlappingLayout(layout);                                                         
3230                                                                                                          
3231         if (!workspaceInModalState()) {                                                                  
3232             mLauncher.getDragLayer().showPageHints();                                                    
3233         }                                                                                                
3234     }                                                                                                    
3235                                                                                                          
3236     /** Return a rect that has the cellWidth/cellHeight (left, top), and                                 
3237      * widthGap/heightGap (right, bottom) */                                                             
3238     static Rect getCellLayoutMetrics(Launcher launcher, int orientation) {                               
3239         LauncherAppState app = LauncherAppState.getInstance();                                           
3240         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                    
3241                                                                                                          
3242         Display display = launcher.getWindowManager().getDefaultDisplay();                               
3243         Point smallestSize = new Point();                                                                
3244         Point largestSize = new Point();                                                                 
3245         display.getCurrentSizeRange(smallestSize, largestSize);                                          
3246         int countX = (int) grid.numColumns;                                                              
3247         int countY = (int) grid.numRows;                                                                 
3248         if (orientation == CellLayout.LANDSCAPE) {                                                       
3249             if (mLandscapeCellLayoutMetrics == null) {                                                   
3250                 Rect padding = grid.getWorkspacePadding(CellLayout.LANDSCAPE);                           
3251                 int width = largestSize.x - padding.left - padding.right;                                
3252                 int height = smallestSize.y - padding.top - padding.bottom;                              
3253                 mLandscapeCellLayoutMetrics = new Rect();                                                
3254                 mLandscapeCellLayoutMetrics.set(                                                         
3255                         grid.calculateCellWidth(width, countX),                                          
3256                         grid.calculateCellHeight(height, countY), 0, 0);                                 
3257             }                                                                                            
3258             return mLandscapeCellLayoutMetrics;                                                          
3259         } else if (orientation == CellLayout.PORTRAIT) {                                                 
3260             if (mPortraitCellLayoutMetrics == null) {                                                    
3261                 Rect padding = grid.getWorkspacePadding(CellLayout.PORTRAIT);                            
3262                 int width = smallestSize.x - padding.left - padding.right;                               
3263                 int height = largestSize.y - padding.top - padding.bottom;                               
3264                 mPortraitCellLayoutMetrics = new Rect();                                                 
3265                 mPortraitCellLayoutMetrics.set(                                                          
3266                         grid.calculateCellWidth(width, countX),                                          
3267                         grid.calculateCellHeight(height, countY), 0, 0);                                 
3268             }                                                                                            
3269             return mPortraitCellLayoutMetrics;                                                           
3270         }                                                                                                
3271         return null;                                                                                     
3272     }                                                                                                    
3273                                                                                                          
3274     public void onDragExit(DragObject d) {                                                               
3275         mDragEnforcer.onDragExit();                                                                      
3276                                                                                                          
3277         // Here we store the final page that will be dropped to, if the workspace in fact                
3278         // receives the drop                                                                             
3279         if (mInScrollArea) {                                                                             
3280             if (isPageMoving()) {                                                                        
3281                 // If the user drops while the page is scrolling, we should use that page as the         
3282                 // destination instead of the page that is being hovered over.                           
3283                 mDropToLayout = (CellLayout) getPageAt(getNextPage());                                   
3284             } else {                                                                                     
3285                 mDropToLayout = mDragOverlappingLayout;                                                  
3286             }                                                                                            
3287         } else {                                                                                         
3288             mDropToLayout = mDragTargetLayout;                                                           
3289         }                                                                                                
3290                                                                                                          
3291         if (mDragMode == DRAG_MODE_CREATE_FOLDER) {                                                      
3292             mCreateUserFolderOnDrop = true;                                                              
3293         } else if (mDragMode == DRAG_MODE_ADD_TO_FOLDER) {                                               
3294             mAddToExistingFolderOnDrop = true;                                                           
3295         }                                                                                                
3296                                                                                                          
3297         // Reset the scroll area and previous drag target                                                
3298         onResetScrollArea();                                                                             
3299         setCurrentDropLayout(null);                                                                      
3300         setCurrentDragOverlappingLayout(null);                                                           
3301                                                                                                          
3302         mSpringLoadedDragController.cancel();                                                            
3303                                                                                                          
3304         if (!mIsPageMoving) {                                                                            
3305             hideOutlines();                                                                              
3306         }                                                                                                
3307         mLauncher.getDragLayer().hidePageHints();                                                        
3308     }                                                                                                    
3309                                                                                                          
3310     void setCurrentDropLayout(CellLayout layout) {                                                       
3311         if (mDragTargetLayout != null) {                                                                 
3312             mDragTargetLayout.revertTempState();                                                         
3313             mDragTargetLayout.onDragExit();                                                              
3314         }                                                                                                
3315         mDragTargetLayout = layout;                                                                      
3316         if (mDragTargetLayout != null) {                                                                 
3317             mDragTargetLayout.onDragEnter();                                                             
3318         }                                                                                                
3319         cleanupReorder(true);                                                                            
3320         cleanupFolderCreation();                                                                         
3321         setCurrentDropOverCell(-1, -1);                                                                  
3322     }                                                                                                    
3323                                                                                                          
3324     void setCurrentDragOverlappingLayout(CellLayout layout) {                                            
3325         if (mDragOverlappingLayout != null) {                                                            
3326             mDragOverlappingLayout.setIsDragOverlapping(false);                                          
3327         }                                                                                                
3328         mDragOverlappingLayout = layout;                                                                 
3329         if (mDragOverlappingLayout != null) {                                                            
3330             mDragOverlappingLayout.setIsDragOverlapping(true);                                           
3331         }                                                                                                
3332         invalidate();                                                                                    
3333     }                                                                                                    
3334                                                                                                          
3335     void setCurrentDropOverCell(int x, int y) {                                                          
3336         if (x != mDragOverX || y != mDragOverY) {                                                        
3337             mDragOverX = x;                                                                              
3338             mDragOverY = y;                                                                              
3339             setDragMode(DRAG_MODE_NONE);                                                                 
3340         }                                                                                                
3341     }                                                                                                    
3342                                                                                                          
3343     void setDragMode(int dragMode) {                                                                     
3344         if (dragMode != mDragMode) {                                                                     
3345             if (dragMode == DRAG_MODE_NONE) {                                                            
3346                 cleanupAddToFolder();                                                                    
3347                 // We don't want to cancel the re-order alarm every time the target cell changes         
3348                 // as this feels to slow / unresponsive.                                                 
3349                 cleanupReorder(false);                                                                   
3350                 cleanupFolderCreation();                                                                 
3351             } else if (dragMode == DRAG_MODE_ADD_TO_FOLDER) {                                            
3352                 cleanupReorder(true);                                                                    
3353                 cleanupFolderCreation();                                                                 
3354             } else if (dragMode == DRAG_MODE_CREATE_FOLDER) {                                            
3355                 cleanupAddToFolder();                                                                    
3356                 cleanupReorder(true);                                                                    
3357             } else if (dragMode == DRAG_MODE_REORDER) {                                                  
3358                 cleanupAddToFolder();                                                                    
3359                 cleanupFolderCreation();                                                                 
3360             }                                                                                            
3361             mDragMode = dragMode;                                                                        
3362         }                                                                                                
3363     }                                                                                                    
3364                                                                                                          
3365     private void cleanupFolderCreation() {                                                               
3366         if (mDragFolderRingAnimator != null) {                                                           
3367             mDragFolderRingAnimator.animateToNaturalState();                                             
3368             mDragFolderRingAnimator = null;                                                              
3369         }                                                                                                
3370         mFolderCreationAlarm.setOnAlarmListener(null);                                                   
3371         mFolderCreationAlarm.cancelAlarm();                                                              
3372     }                                                                                                    
3373                                                                                                          
3374     private void cleanupAddToFolder() {                                                                  
3375         if (mDragOverFolderIcon != null) {                                                               
3376             mDragOverFolderIcon.onDragExit(null);                                                        
3377             mDragOverFolderIcon = null;                                                                  
3378         }                                                                                                
3379     }                                                                                                    
3380                                                                                                          
3381     private void cleanupReorder(boolean cancelAlarm) {                                                   
3382         // Any pending reorders are canceled                                                             
3383         if (cancelAlarm) {                                                                               
3384             mReorderAlarm.cancelAlarm();                                                                 
3385         }                                                                                                
3386         mLastReorderX = -1;                                                                              
3387         mLastReorderY = -1;                                                                              
3388     }                                                                                                    
3389                                                                                                          
3390    /*                                                                                                    
3391     *                                                                                                    
3392     * Convert the 2D coordinate xy from the parent View's coordinate space to this CellLayout's          
3393     * coordinate space. The argument xy is modified with the return result.                              
3394     *                                                                                                    
3395     * if cachedInverseMatrix is not null, this method will just use that matrix instead of               
3396     * computing it itself; we use this to avoid redundant matrix inversions in                           
3397     * findMatchingPageForDragOver                                                                        
3398     *                                                                                                    
3399     */                                                                                                   
3400    void mapPointFromSelfToChild(View v, float[] xy, Matrix cachedInverseMatrix) {                        
3401        xy[0] = xy[0] - v.getLeft();                                                                      
3402        xy[1] = xy[1] - v.getTop();                                                                       
3403    }                                                                                                     
3404                                                                                                          
3405    boolean isPointInSelfOverHotseat(int x, int y, Rect r) {                                              
3406        if (r == null) {                                                                                  
3407            r = new Rect();                                                                               
3408        }                                                                                                 
3409        mTempPt[0] = x;                                                                                   
3410        mTempPt[1] = y;                                                                                   
3411        mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempPt, true);                   
3412                                                                                                          
3413        LauncherAppState app = LauncherAppState.getInstance();                                            
3414        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                     
3415        r = grid.getHotseatRect();                                                                        
3416        if (r.contains(mTempPt[0], mTempPt[1])) {                                                         
3417            return true;                                                                                  
3418        }                                                                                                 
3419        return false;                                                                                     
3420    }                                                                                                     
3421                                                                                                          
3422    void mapPointFromSelfToHotseatLayout(Hotseat hotseat, float[] xy) {                                   
3423        mTempPt[0] = (int) xy[0];                                                                         
3424        mTempPt[1] = (int) xy[1];                                                                         
3425        mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempPt, true);                   
3426        mLauncher.getDragLayer().mapCoordInSelfToDescendent(hotseat.getLayout(), mTempPt);                
3427                                                                                                          
3428        xy[0] = mTempPt[0];                                                                               
3429        xy[1] = mTempPt[1];                                                                               
3430    }                                                                                                     
3431                                                                                                          
3432    /*                                                                                                    
3433     *                                                                                                    
3434     * Convert the 2D coordinate xy from this CellLayout's coordinate space to                            
3435     * the parent View's coordinate space. The argument xy is modified with the return result.            
3436     *                                                                                                    
3437     */                                                                                                   
3438    void mapPointFromChildToSelf(View v, float[] xy) {                                                    
3439        xy[0] += v.getLeft();                                                                             
3440        xy[1] += v.getTop();                                                                              
3441    }                                                                                                     
3442                                                                                                          
3443    static private float squaredDistance(float[] point1, float[] point2) {                                
3444         float distanceX = point1[0] - point2[0];                                                         
3445         float distanceY = point2[1] - point2[1];                                                         
3446         return distanceX * distanceX + distanceY * distanceY;                                            
3447    }                                                                                                     
3448                                                                                                          
3449     /*                                                                                                   
3450      *                                                                                                   
3451      * This method returns the CellLayout that is currently being dragged to. In order to drag           
3452      * to a CellLayout, either the touch point must be directly over the CellLayout, or as a second      
3453      * strategy, we see if the dragView is overlapping any CellLayout and choose the closest one         
3454      *                                                                                                   
3455      * Return null if no CellLayout is currently being dragged over                                      
3456      *                                                                                                   
3457      */                                                                                                  
3458     private CellLayout findMatchingPageForDragOver(                                                      
3459             DragView dragView, float originX, float originY, boolean exact) {                            
3460         // We loop through all the screens (ie CellLayouts) and see which ones overlap                   
3461         // with the item being dragged and then choose the one that's closest to the touch point         
3462         final int screenCount = getChildCount();                                                         
3463         CellLayout bestMatchingScreen = null;                                                            
3464         float smallestDistSoFar = Float.MAX_VALUE;                                                       
3465                                                                                                          
3466         for (int i = 0; i < screenCount; i++) {                                                          
3467             // The custom content screen is not a valid drag over option                                 
3468             if (mScreenOrder.get(i) == CUSTOM_CONTENT_SCREEN_ID) {                                       
3469                 continue;                                                                                
3470             }                                                                                            
3471                                                                                                          
3472             CellLayout cl = (CellLayout) getChildAt(i);                                                  
3473                                                                                                          
3474             final float[] touchXy = {originX, originY};                                                  
3475             // Transform the touch coordinates to the CellLayout's local coordinates                     
3476             // If the touch point is within the bounds of the cell layout, we can return immediately     
3477             cl.getMatrix().invert(mTempInverseMatrix);                                                   
3478             mapPointFromSelfToChild(cl, touchXy, mTempInverseMatrix);                                    
3479                                                                                                          
3480             if (touchXy[0] >= 0 && touchXy[0] <= cl.getWidth() &&                                        
3481                     touchXy[1] >= 0 && touchXy[1] <= cl.getHeight()) {                                   
3482                 return cl;                                                                               
3483             }                                                                                            
3484                                                                                                          
3485             if (!exact) {                                                                                
3486                 // Get the center of the cell layout in screen coordinates                               
3487                 final float[] cellLayoutCenter = mTempCellLayoutCenterCoordinates;                       
3488                 cellLayoutCenter[0] = cl.getWidth()/2;                                                   
3489                 cellLayoutCenter[1] = cl.getHeight()/2;                                                  
3490                 mapPointFromChildToSelf(cl, cellLayoutCenter);                                           
3491                                                                                                          
3492                 touchXy[0] = originX;                                                                    
3493                 touchXy[1] = originY;                                                                    
3494                                                                                                          
3495                 // Calculate the distance between the center of the CellLayout                           
3496                 // and the touch point                                                                   
3497                 float dist = squaredDistance(touchXy, cellLayoutCenter);                                 
3498                                                                                                          
3499                 if (dist < smallestDistSoFar) {                                                          
3500                     smallestDistSoFar = dist;                                                            
3501                     bestMatchingScreen = cl;                                                             
3502                 }                                                                                        
3503             }                                                                                            
3504         }                                                                                                
3505         return bestMatchingScreen;                                                                       
3506     }                                                                                                    
3507                                                                                                          
3508     // This is used to compute the visual center of the dragView. This point is then                     
3509     // used to visualize drop locations and determine where to drop an item. The idea is that            
3510     // the visual center represents the user's interpretation of where the item is, and hence            
3511     // is the appropriate point to use when determining drop location.                                   
3512     private float[] getDragViewVisualCenter(int x, int y, int xOffset, int yOffset,                      
3513             DragView dragView, float[] recycle) {                                                        
3514         float res[];                                                                                     
3515         if (recycle == null) {                                                                           
3516             res = new float[2];                                                                          
3517         } else {                                                                                         
3518             res = recycle;                                                                               
3519         }                                                                                                
3520                                                                                                          
3521         // First off, the drag view has been shifted in a way that is not represented in the             
3522         // x and y values or the x/yOffsets. Here we account for that shift.                             
3523         x += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetX);                              
3524         y += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY);                              
3525                                                                                                          
3526         // These represent the visual top and left of drag view if a dragRect was provided.              
3527         // If a dragRect was not provided, then they correspond to the actual view left and              
3528         // top, as the dragRect is in that case taken to be the entire dragView.                         
3529         // R.dimen.dragViewOffsetY.                                                                      
3530         int left = x - xOffset;                                                                          
3531         int top = y - yOffset;                                                                           
3532                                                                                                          
3533         // In order to find the visual center, we shift by half the dragRect                             
3534         res[0] = left + dragView.getDragRegion().width() / 2;                                            
3535         res[1] = top + dragView.getDragRegion().height() / 2;                                            
3536                                                                                                          
3537         return res;                                                                                      
3538     }                                                                                                    
3539                                                                                                          
3540     private boolean isDragWidget(DragObject d) {                                                         
3541         return (d.dragInfo instanceof LauncherAppWidgetInfo ||                                           
3542                 d.dragInfo instanceof PendingAddWidgetInfo);                                             
3543     }                                                                                                    
3544     private boolean isExternalDragWidget(DragObject d) {                                                 
3545         return d.dragSource != this && isDragWidget(d);                                                  
3546     }                                                                                                    
3547                                                                                                          
3548     public void onDragOver(DragObject d) {                                                               
3549         // Skip drag over events while we are dragging over side pages                                   
3550         if (mInScrollArea || !transitionStateShouldAllowDrop()) return;                                  
3551                                                                                                          
3552         Rect r = new Rect();                                                                             
3553         CellLayout layout = null;                                                                        
3554         ItemInfo item = (ItemInfo) d.dragInfo;                                                           
3555         if (item == null) {                                                                              
3556             if (LauncherAppState.isDogfoodBuild()) {                                                     
3557                 throw new NullPointerException("DragObject has null info");                              
3558             }                                                                                            
3559             return;                                                                                      
3560         }                                                                                                
3561                                                                                                          
3562         // Ensure that we have proper spans for the item that we are dropping                            
3563         if (item.spanX < 0 || item.spanY < 0) throw new RuntimeException("Improper spans found");        
3564         mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset,                  
3565             d.dragView, mDragViewVisualCenter);                                                          
3566                                                                                                          
3567         final View child = (mDragInfo == null) ? null : mDragInfo.cell;                                  
3568         // Identify whether we have dragged over a side page                                             
3569         if (workspaceInModalState()) {                                                                   
3570             if (mLauncher.getHotseat() != null && !isExternalDragWidget(d)) {                            
3571                 if (isPointInSelfOverHotseat(d.x, d.y, r)) {                                             
3572                     layout = mLauncher.getHotseat().getLayout();                                         
3573                 }                                                                                        
3574             }                                                                                            
3575             if (layout == null) {                                                                        
3576                 layout = findMatchingPageForDragOver(d.dragView, d.x, d.y, false);                       
3577             }                                                                                            
3578             if (layout != mDragTargetLayout) {                                                           
3579                 setCurrentDropLayout(layout);                                                            
3580                 setCurrentDragOverlappingLayout(layout);                                                 
3581                                                                                                          
3582                 boolean isInSpringLoadedMode = (mState == State.SPRING_LOADED);                          
3583                 if (isInSpringLoadedMode) {                                                              
3584                     if (mLauncher.isHotseatLayout(layout)) {                                             
3585                         mSpringLoadedDragController.cancel();                                            
3586                     } else {                                                                             
3587                         mSpringLoadedDragController.setAlarm(mDragTargetLayout);                         
3588                     }                                                                                    
3589                 }                                                                                        
3590             }                                                                                            
3591         } else {                                                                                         
3592             // Test to see if we are over the hotseat otherwise just use the current page                
3593             if (mLauncher.getHotseat() != null && !isDragWidget(d)) {                                    
3594                 if (isPointInSelfOverHotseat(d.x, d.y, r)) {                                             
3595                     layout = mLauncher.getHotseat().getLayout();                                         
3596                 }                                                                                        
3597             }                                                                                            
3598             if (layout == null) {                                                                        
3599                 layout = getCurrentDropLayout();                                                         
3600             }                                                                                            
3601             if (layout != mDragTargetLayout) {                                                           
3602                 setCurrentDropLayout(layout);                                                            
3603                 setCurrentDragOverlappingLayout(layout);                                                 
3604             }                                                                                            
3605         }                                                                                                
3606                                                                                                          
3607         // Handle the drag over                                                                          
3608         if (mDragTargetLayout != null) {                                                                 
3609             // We want the point to be mapped to the dragTarget.                                         
3610             if (mLauncher.isHotseatLayout(mDragTargetLayout)) {                                          
3611                 mapPointFromSelfToHotseatLayout(mLauncher.getHotseat(), mDragViewVisualCenter);          
3612             } else {                                                                                     
3613                 mapPointFromSelfToChild(mDragTargetLayout, mDragViewVisualCenter, null);                 
3614             }                                                                                            
3615                                                                                                          
3616             ItemInfo info = (ItemInfo) d.dragInfo;                                                       
3617                                                                                                          
3618             int minSpanX = item.spanX;                                                                   
3619             int minSpanY = item.spanY;                                                                   
3620             if (item.minSpanX > 0 && item.minSpanY > 0) {                                                
3621                 minSpanX = item.minSpanX;                                                                
3622                 minSpanY = item.minSpanY;                                                                
3623             }                                                                                            
3624                                                                                                          
3625             mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],                                
3626                     (int) mDragViewVisualCenter[1], minSpanX, minSpanY,                                  
3627                     mDragTargetLayout, mTargetCell);                                                     
3628             int reorderX = mTargetCell[0];                                                               
3629             int reorderY = mTargetCell[1];                                                               
3630                                                                                                          
3631             setCurrentDropOverCell(mTargetCell[0], mTargetCell[1]);                                      
3632                                                                                                          
3633             float targetCellDistance = mDragTargetLayout.getDistanceFromCell(                            
3634                     mDragViewVisualCenter[0], mDragViewVisualCenter[1], mTargetCell);                    
3635                                                                                                          
3636             final View dragOverView = mDragTargetLayout.getChildAt(mTargetCell[0],                       
3637                     mTargetCell[1]);                                                                     
3638                                                                                                          
3639             manageFolderFeedback(info, mDragTargetLayout, mTargetCell,                                   
3640                     targetCellDistance, dragOverView);                                                   
3641                                                                                                          
3642             boolean nearestDropOccupied = mDragTargetLayout.isNearestDropLocationOccupied((int)          
3643                     mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], item.spanX,                
3644                     item.spanY, child, mTargetCell);                                                     
3645                                                                                                          
3646             if (!nearestDropOccupied) {                                                                  
3647                 mDragTargetLayout.visualizeDropLocation(child, mDragOutline,                             
3648                         (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1],                  
3649                         mTargetCell[0], mTargetCell[1], item.spanX, item.spanY, false,                   
3650                         d.dragView.getDragVisualizeOffset(), d.dragView.getDragRegion());                
3651             } else if ((mDragMode == DRAG_MODE_NONE || mDragMode == DRAG_MODE_REORDER)                   
3652                     && !mReorderAlarm.alarmPending() && (mLastReorderX != reorderX ||                    
3653                     mLastReorderY != reorderY)) {                                                        
3654                                                                                                          
3655                 int[] resultSpan = new int[2];                                                           
3656                 mDragTargetLayout.performReorder((int) mDragViewVisualCenter[0],                         
3657                         (int) mDragViewVisualCenter[1], minSpanX, minSpanY, item.spanX, item.spanY,      
3658                         child, mTargetCell, resultSpan, CellLayout.MODE_SHOW_REORDER_HINT);              
3659                                                                                                          
3660                 // Otherwise, if we aren't adding to or creating a folder and there's no pending         
3661                 // reorder, then we schedule a reorder                                                   
3662                 ReorderAlarmListener listener = new ReorderAlarmListener(mDragViewVisualCenter,          
3663                         minSpanX, minSpanY, item.spanX, item.spanY, d.dragView, child);                  
3664                 mReorderAlarm.setOnAlarmListener(listener);                                              
3665                 mReorderAlarm.setAlarm(REORDER_TIMEOUT);                                                 
3666             }                                                                                            
3667                                                                                                          
3668             if (mDragMode == DRAG_MODE_CREATE_FOLDER || mDragMode == DRAG_MODE_ADD_TO_FOLDER ||          
3669                     !nearestDropOccupied) {                                                              
3670                 if (mDragTargetLayout != null) {                                                         
3671                     mDragTargetLayout.revertTempState();                                                 
3672                 }                                                                                        
3673             }                                                                                            
3674         }                                                                                                
3675     }                                                                                                    
3676                                                                                                          
3677     private void manageFolderFeedback(ItemInfo info, CellLayout targetLayout,                            
3678             int[] targetCell, float distance, View dragOverView) {                                       
3679         boolean userFolderPending = willCreateUserFolder(info, targetLayout, targetCell, distance,       
3680                 false);                                                                                  
3681                                                                                                          
3682         if (mDragMode == DRAG_MODE_NONE && userFolderPending &&                                          
3683                 !mFolderCreationAlarm.alarmPending()) {                                                  
3684             mFolderCreationAlarm.setOnAlarmListener(new                                                  
3685                     FolderCreationAlarmListener(targetLayout, targetCell[0], targetCell[1]));            
3686             mFolderCreationAlarm.setAlarm(FOLDER_CREATION_TIMEOUT);                                      
3687             return;                                                                                      
3688         }                                                                                                
3689                                                                                                          
3690         boolean willAddToFolder =                                                                        
3691                 willAddToExistingUserFolder(info, targetLayout, targetCell, distance);                   
3692                                                                                                          
3693         if (willAddToFolder && mDragMode == DRAG_MODE_NONE) {                                            
3694             mDragOverFolderIcon = ((FolderIcon) dragOverView);                                           
3695             mDragOverFolderIcon.onDragEnter(info);                                                       
3696             if (targetLayout != null) {                                                                  
3697                 targetLayout.clearDragOutlines();                                                        
3698             }                                                                                            
3699             setDragMode(DRAG_MODE_ADD_TO_FOLDER);                                                        
3700             return;                                                                                      
3701         }                                                                                                
3702                                                                                                          
3703         if (mDragMode == DRAG_MODE_ADD_TO_FOLDER && !willAddToFolder) {                                  
3704             setDragMode(DRAG_MODE_NONE);                                                                 
3705         }                                                                                                
3706         if (mDragMode == DRAG_MODE_CREATE_FOLDER && !userFolderPending) {                                
3707             setDragMode(DRAG_MODE_NONE);                                                                 
3708         }                                                                                                
3709                                                                                                          
3710         return;                                                                                          
3711     }                                                                                                    
3712                                                                                                          
3713     class FolderCreationAlarmListener implements OnAlarmListener {                                       
3714         CellLayout layout;                                                                               
3715         int cellX;                                                                                       
3716         int cellY;                                                                                       
3717                                                                                                          
3718         public FolderCreationAlarmListener(CellLayout layout, int cellX, int cellY) {                    
3719             this.layout = layout;                                                                        
3720             this.cellX = cellX;                                                                          
3721             this.cellY = cellY;                                                                          
3722         }                                                                                                
3723                                                                                                          
3724         public void onAlarm(Alarm alarm) {                                                               
3725             if (mDragFolderRingAnimator != null) {                                                       
3726                 // This shouldn't happen ever, but just in case, make sure we clean up the mess.         
3727                 mDragFolderRingAnimator.animateToNaturalState();                                         
3728             }                                                                                            
3729             mDragFolderRingAnimator = new FolderRingAnimator(mLauncher, null);                           
3730             mDragFolderRingAnimator.setCell(cellX, cellY);                                               
3731             mDragFolderRingAnimator.setCellLayout(layout);                                               
3732             mDragFolderRingAnimator.animateToAcceptState();                                              
3733             layout.showFolderAccept(mDragFolderRingAnimator);                                            
3734             layout.clearDragOutlines();                                                                  
3735             setDragMode(DRAG_MODE_CREATE_FOLDER);                                                        
3736         }                                                                                                
3737     }                                                                                                    
3738                                                                                                          
3739     class ReorderAlarmListener implements OnAlarmListener {                                              
3740         float[] dragViewCenter;                                                                          
3741         int minSpanX, minSpanY, spanX, spanY;                                                            
3742         DragView dragView;                                                                               
3743         View child;                                                                                      
3744                                                                                                          
3745         public ReorderAlarmListener(float[] dragViewCenter, int minSpanX, int minSpanY, int spanX,       
3746                 int spanY, DragView dragView, View child) {                                              
3747             this.dragViewCenter = dragViewCenter;                                                        
3748             this.minSpanX = minSpanX;                                                                    
3749             this.minSpanY = minSpanY;                                                                    
3750             this.spanX = spanX;                                                                          
3751             this.spanY = spanY;                                                                          
3752             this.child = child;                                                                          
3753             this.dragView = dragView;                                                                    
3754         }                                                                                                
3755                                                                                                          
3756         public void onAlarm(Alarm alarm) {                                                               
3757             int[] resultSpan = new int[2];                                                               
3758             mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],                                
3759                     (int) mDragViewVisualCenter[1], minSpanX, minSpanY, mDragTargetLayout,               
3760                     mTargetCell);                                                                        
3761             mLastReorderX = mTargetCell[0];                                                              
3762             mLastReorderY = mTargetCell[1];                                                              
3763                                                                                                          
3764             mTargetCell = mDragTargetLayout.performReorder((int) mDragViewVisualCenter[0],               
3765                 (int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY,                        
3766                 child, mTargetCell, resultSpan, CellLayout.MODE_DRAG_OVER);                              
3767                                                                                                          
3768             if (mTargetCell[0] < 0 || mTargetCell[1] < 0) {                                              
3769                 mDragTargetLayout.revertTempState();                                                     
3770             } else {                                                                                     
3771                 setDragMode(DRAG_MODE_REORDER);                                                          
3772             }                                                                                            
3773                                                                                                          
3774             boolean resize = resultSpan[0] != spanX || resultSpan[1] != spanY;                           
3775             mDragTargetLayout.visualizeDropLocation(child, mDragOutline,                                 
3776                 (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1],                          
3777                 mTargetCell[0], mTargetCell[1], resultSpan[0], resultSpan[1], resize,                    
3778                 dragView.getDragVisualizeOffset(), dragView.getDragRegion());                            
3779         }                                                                                                
3780     }                                                                                                    
3781                                                                                                          
3782     @Override                                                                                            
3783     public void getHitRectRelativeToDragLayer(Rect outRect) {                                            
3784         // We want the workspace to have the whole area of the display (it will find the correct         
3785         // cell layout to drop to in the existing drag/drop logic.                                       
3786         mLauncher.getDragLayer().getDescendantRectRelativeToSelf(this, outRect);                         
3787     }                                                                                                    
3788                                                                                                          
3789     /**                                                                                                  
3790      * Add the item specified by dragInfo to the given layout.                                           
3791      * @return true if successful                                                                        
3792      */                                                                                                  
3793     public boolean addExternalItemToScreen(ItemInfo dragInfo, CellLayout layout) {                       
3794         if (layout.findCellForSpan(mTempEstimate, dragInfo.spanX, dragInfo.spanY)) {                     
3795             onDropExternal(dragInfo.dropPos, (ItemInfo) dragInfo, (CellLayout) layout, false);           
3796             return true;                                                                                 
3797         }                                                                                                
3798         mLauncher.showOutOfSpaceMessage(mLauncher.isHotseatLayout(layout));                              
3799         return false;                                                                                    
3800     }                                                                                                    
3801                                                                                                          
3802     private void onDropExternal(int[] touchXY, Object dragInfo,                                          
3803             CellLayout cellLayout, boolean insertAtFirst) {                                              
3804         onDropExternal(touchXY, dragInfo, cellLayout, insertAtFirst, null);                              
3805     }                                                                                                    
3806                                                                                                          
3807     /**                                                                                                  
3808      * Drop an item that didn't originate on one of the workspace screens.                               
3809      * It may have come from Launcher (e.g. from all apps or customize), or it may have                  
3810      * come from another app altogether.                                                                 
3811      *                                                                                                   
3812      * NOTE: This can also be called when we are outside of a drag event, when we want                   
3813      * to add an item to one of the workspace screens.                                                   
3814      */                                                                                                  
3815     private void onDropExternal(final int[] touchXY, final Object dragInfo,                              
3816             final CellLayout cellLayout, boolean insertAtFirst, DragObject d) {                          
3817         final Runnable exitSpringLoadedRunnable = new Runnable() {                                       
3818             @Override                                                                                    
3819             public void run() {                                                                          
3820                 mLauncher.exitSpringLoadedDragModeDelayed(true,                                          
3821                         Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);                            
3822             }                                                                                            
3823         };                                                                                               
3824                                                                                                          
3825         ItemInfo info = (ItemInfo) dragInfo;                                                             
3826         int spanX = info.spanX;                                                                          
3827         int spanY = info.spanY;                                                                          
3828         if (mDragInfo != null) {                                                                         
3829             spanX = mDragInfo.spanX;                                                                     
3830             spanY = mDragInfo.spanY;                                                                     
3831         }                                                                                                
3832                                                                                                          
3833         final long container = mLauncher.isHotseatLayout(cellLayout) ?                                   
3834                 LauncherSettings.Favorites.CONTAINER_HOTSEAT :                                           
3835                     LauncherSettings.Favorites.CONTAINER_DESKTOP;                                        
3836         final long screenId = getIdForScreen(cellLayout);                                                
3837         if (!mLauncher.isHotseatLayout(cellLayout)                                                       
3838                 && screenId != getScreenIdForPageIndex(mCurrentPage)                                     
3839                 && mState != State.SPRING_LOADED) {                                                      
3840             snapToScreenId(screenId, null);                                                              
3841         }                                                                                                
3842                                                                                                          
3843         if (info instanceof PendingAddItemInfo) {                                                        
3844             final PendingAddItemInfo pendingInfo = (PendingAddItemInfo) dragInfo;                        
3845                                                                                                          
3846             boolean findNearestVacantCell = true;                                                        
3847             if (pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {                 
3848                 mTargetCell = findNearestArea((int) touchXY[0], (int) touchXY[1], spanX, spanY,          
3849                         cellLayout, mTargetCell);                                                        
3850                 float distance = cellLayout.getDistanceFromCell(mDragViewVisualCenter[0],                
3851                         mDragViewVisualCenter[1], mTargetCell);                                          
3852                 if (willCreateUserFolder((ItemInfo) d.dragInfo, cellLayout, mTargetCell,                 
3853                         distance, true) || willAddToExistingUserFolder((ItemInfo) d.dragInfo,            
3854                                 cellLayout, mTargetCell, distance)) {                                    
3855                     findNearestVacantCell = false;                                                       
3856                 }                                                                                        
3857             }                                                                                            
3858                                                                                                          
3859             final ItemInfo item = (ItemInfo) d.dragInfo;                                                 
3860             boolean updateWidgetSize = false;                                                            
3861             if (findNearestVacantCell) {                                                                 
3862                 int minSpanX = item.spanX;                                                               
3863                 int minSpanY = item.spanY;                                                               
3864                 if (item.minSpanX > 0 && item.minSpanY > 0) {                                            
3865                     minSpanX = item.minSpanX;                                                            
3866                     minSpanY = item.minSpanY;                                                            
3867                 }                                                                                        
3868                 int[] resultSpan = new int[2];                                                           
3869                 mTargetCell = cellLayout.performReorder((int) mDragViewVisualCenter[0],                  
3870                         (int) mDragViewVisualCenter[1], minSpanX, minSpanY, info.spanX, info.spanY,      
3871                         null, mTargetCell, resultSpan, CellLayout.MODE_ON_DROP_EXTERNAL);                
3872                                                                                                          
3873                 if (resultSpan[0] != item.spanX || resultSpan[1] != item.spanY) {                        
3874                     updateWidgetSize = true;                                                             
3875                 }                                                                                        
3876                 item.spanX = resultSpan[0];                                                              
3877                 item.spanY = resultSpan[1];                                                              
3878             }                                                                                            
3879                                                                                                          
3880             Runnable onAnimationCompleteRunnable = new Runnable() {                                      
3881                 @Override                                                                                
3882                 public void run() {                                                                      
3883                     // Normally removeExtraEmptyScreen is called in Workspace#onDragEnd, but when        
3884                     // adding an item that may not be dropped right away (due to a config activity)      
3885                     // we defer the removal until the activity returns.                                  
3886                     deferRemoveExtraEmptyScreen();                                                       
3887                                                                                                          
3888                     // When dragging and dropping from customization tray, we deal with creating         
3889                     // widgets/shortcuts/folders in a slightly different way                             
3890                     switch (pendingInfo.itemType) {                                                      
3891                     case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                                 
3892                         int span[] = new int[2];                                                         
3893                         span[0] = item.spanX;                                                            
3894                         span[1] = item.spanY;                                                            
3895                         mLauncher.addAppWidgetFromDrop((PendingAddWidgetInfo) pendingInfo,               
3896                                 container, screenId, mTargetCell, span, null);                           
3897                         break;                                                                           
3898                     case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                  
3899                         mLauncher.processShortcutFromDrop(pendingInfo.componentName,                     
3900                                 container, screenId, mTargetCell, null);                                 
3901                         break;                                                                           
3902                     default:                                                                             
3903                         throw new IllegalStateException("Unknown item type: " +                          
3904                                 pendingInfo.itemType);                                                   
3905                     }                                                                                    
3906                 }                                                                                        
3907             };                                                                                           
3908             View finalView = pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET      
3909                     ? ((PendingAddWidgetInfo) pendingInfo).boundWidget : null;                           
3910                                                                                                          
3911             if (finalView instanceof AppWidgetHostView && updateWidgetSize) {                            
3912                 AppWidgetHostView awhv = (AppWidgetHostView) finalView;                                  
3913                 AppWidgetResizeFrame.updateWidgetSizeRanges(awhv, mLauncher, item.spanX,                 
3914                         item.spanY);                                                                     
3915             }                                                                                            
3916                                                                                                          
3917             int animationStyle = ANIMATE_INTO_POSITION_AND_DISAPPEAR;                                    
3918             if (pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET &&                
3919                     ((PendingAddWidgetInfo) pendingInfo).info.configure != null) {                       
3920                 animationStyle = ANIMATE_INTO_POSITION_AND_REMAIN;                                       
3921             }                                                                                            
3922             animateWidgetDrop(info, cellLayout, d.dragView, onAnimationCompleteRunnable,                 
3923                     animationStyle, finalView, true);                                                    
3924         } else {                                                                                         
3925             // This is for other drag/drop cases, like dragging from All Apps                            
3926             View view = null;                                                                            
3927                                                                                                          
3928             switch (info.itemType) {                                                                     
3929             case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                                       
3930             case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                          
3931                 if (info.container == NO_ID && info instanceof AppInfo) {                                
3932                     // Came from all apps -- make a copy                                                 
3933                     info = new ShortcutInfo((AppInfo) info);                                             
3934                 }                                                                                        
3935                 view = mLauncher.createShortcut(R.layout.application, cellLayout,                        
3936                         (ShortcutInfo) info);                                                            
3937                 break;                                                                                   
3938             case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                            
3939                 view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher, cellLayout,                   
3940                         (FolderInfo) info, mIconCache);                                                  
3941                 break;                                                                                   
3942             default:                                                                                     
3943                 throw new IllegalStateException("Unknown item type: " + info.itemType);                  
3944             }                                                                                            
3945                                                                                                          
3946             // First we find the cell nearest to point at which the item is                              
3947             // dropped, without any consideration to whether there is an item there.                     
3948             if (touchXY != null) {                                                                       
3949                 mTargetCell = findNearestArea((int) touchXY[0], (int) touchXY[1], spanX, spanY,          
3950                         cellLayout, mTargetCell);                                                        
3951                 float distance = cellLayout.getDistanceFromCell(mDragViewVisualCenter[0],                
3952                         mDragViewVisualCenter[1], mTargetCell);                                          
3953                 d.postAnimationRunnable = exitSpringLoadedRunnable;                                      
3954                 if (createUserFolderIfNecessary(view, container, cellLayout, mTargetCell, distance,      
3955                         true, d.dragView, d.postAnimationRunnable)) {                                    
3956                     return;                                                                              
3957                 }                                                                                        
3958                 if (addToExistingFolderIfNecessary(view, cellLayout, mTargetCell, distance, d,           
3959                         true)) {                                                                         
3960                     return;                                                                              
3961                 }                                                                                        
3962             }                                                                                            
3963                                                                                                          
3964             if (touchXY != null) {                                                                       
3965                 // when dragging and dropping, just find the closest free spot                           
3966                 mTargetCell = cellLayout.performReorder((int) mDragViewVisualCenter[0],                  
3967                         (int) mDragViewVisualCenter[1], 1, 1, 1, 1,                                      
3968                         null, mTargetCell, null, CellLayout.MODE_ON_DROP_EXTERNAL);                      
3969             } else {                                                                                     
3970                 cellLayout.findCellForSpan(mTargetCell, 1, 1);                                           
3971             }                                                                                            
3972             // Add the item to DB before adding to screen ensures that the container and other           
3973             // values of the info is properly updated.                                                   
3974             LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screenId,                  
3975                     mTargetCell[0], mTargetCell[1]);                                                     
3976                                                                                                          
3977             addInScreen(view, container, screenId, mTargetCell[0], mTargetCell[1], info.spanX,           
3978                     info.spanY, insertAtFirst);                                                          
3979             cellLayout.onDropChild(view);                                                                
3980             cellLayout.getShortcutsAndWidgets().measureChild(view);                                      
3981                                                                                                          
3982             if (d.dragView != null) {                                                                    
3983                 // We wrap the animation call in the temporary set and reset of the current              
3984                 // cellLayout to its final transform -- this means we animate the drag view to           
3985                 // the correct final location.                                                           
3986                 setFinalTransitionTransform(cellLayout);                                                 
3987                 mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, view,                       
3988                         exitSpringLoadedRunnable, this);                                                 
3989                 resetTransitionTransform(cellLayout);                                                    
3990             }                                                                                            
3991         }                                                                                                
3992     }                                                                                                    
3993                                                                                                          
3994     public Bitmap createWidgetBitmap(ItemInfo widgetInfo, View layout) {                                 
3995         int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(widgetInfo.spanX,                 
3996                 widgetInfo.spanY, widgetInfo, false);                                                    
3997         int visibility = layout.getVisibility();                                                         
3998         layout.setVisibility(VISIBLE);                                                                   
3999                                                                                                          
4000         int width = MeasureSpec.makeMeasureSpec(unScaledSize[0], MeasureSpec.EXACTLY);                   
4001         int height = MeasureSpec.makeMeasureSpec(unScaledSize[1], MeasureSpec.EXACTLY);                  
4002         Bitmap b = Bitmap.createBitmap(unScaledSize[0], unScaledSize[1],                                 
4003                 Bitmap.Config.ARGB_8888);                                                                
4004         mCanvas.setBitmap(b);                                                                            
4005                                                                                                          
4006         layout.measure(width, height);                                                                   
4007         layout.layout(0, 0, unScaledSize[0], unScaledSize[1]);                                           
4008         layout.draw(mCanvas);                                                                            
4009         mCanvas.setBitmap(null);                                                                         
4010         layout.setVisibility(visibility);                                                                
4011         return b;                                                                                        
4012     }                                                                                                    
4013                                                                                                          
4014     private void getFinalPositionForDropAnimation(int[] loc, float[] scaleXY,                            
4015             DragView dragView, CellLayout layout, ItemInfo info, int[] targetCell,                       
4016             boolean external, boolean scale) {                                                           
4017         // Now we animate the dragView, (ie. the widget or shortcut preview) into its final              
4018         // location and size on the home screen.                                                         
4019         int spanX = info.spanX;                                                                          
4020         int spanY = info.spanY;                                                                          
4021                                                                                                          
4022         Rect r = estimateItemPosition(layout, info, targetCell[0], targetCell[1], spanX, spanY);         
4023         loc[0] = r.left;                                                                                 
4024         loc[1] = r.top;                                                                                  
4025                                                                                                          
4026         setFinalTransitionTransform(layout);                                                             
4027         float cellLayoutScale =                                                                          
4028                 mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(layout, loc, true);            
4029         resetTransitionTransform(layout);                                                                
4030                                                                                                          
4031         float dragViewScaleX;                                                                            
4032         float dragViewScaleY;                                                                            
4033         if (scale) {                                                                                     
4034             dragViewScaleX = (1.0f * r.width()) / dragView.getMeasuredWidth();                           
4035             dragViewScaleY = (1.0f * r.height()) / dragView.getMeasuredHeight();                         
4036         } else {                                                                                         
4037             dragViewScaleX = 1f;                                                                         
4038             dragViewScaleY = 1f;                                                                         
4039         }                                                                                                
4040                                                                                                          
4041         // The animation will scale the dragView about its center, so we need to center about            
4042         // the final location.                                                                           
4043         loc[0] -= (dragView.getMeasuredWidth() - cellLayoutScale * r.width()) / 2;                       
4044         loc[1] -= (dragView.getMeasuredHeight() - cellLayoutScale * r.height()) / 2;                     
4045                                                                                                          
4046         scaleXY[0] = dragViewScaleX * cellLayoutScale;                                                   
4047         scaleXY[1] = dragViewScaleY * cellLayoutScale;                                                   
4048     }                                                                                                    
4049                                                                                                          
4050     public void animateWidgetDrop(ItemInfo info, CellLayout cellLayout, DragView dragView,               
4051             final Runnable onCompleteRunnable, int animationType, final View finalView,                  
4052             boolean external) {                                                                          
4053         Rect from = new Rect();                                                                          
4054         mLauncher.getDragLayer().getViewRectRelativeToSelf(dragView, from);                              
4055                                                                                                          
4056         int[] finalPos = new int[2];                                                                     
4057         float scaleXY[] = new float[2];                                                                  
4058         boolean scalePreview = !(info instanceof PendingAddShortcutInfo);                                
4059         getFinalPositionForDropAnimation(finalPos, scaleXY, dragView, cellLayout, info, mTargetCell,     
4060                 external, scalePreview);                                                                 
4061                                                                                                          
4062         Resources res = mLauncher.getResources();                                                        
4063         final int duration = res.getInteger(R.integer.config_dropAnimMaxDuration) - 200;                 
4064                                                                                                          
4065         // In the case where we've prebound the widget, we remove it from the DragLayer                  
4066         if (finalView instanceof AppWidgetHostView && external) {                                        
4067             Log.d(TAG, "6557954 Animate widget drop, final view is appWidgetHostView");                  
4068             mLauncher.getDragLayer().removeView(finalView);                                              
4069         }                                                                                                
4070         if ((animationType == ANIMATE_INTO_POSITION_AND_RESIZE || external) && finalView != null) {      
4071             Bitmap crossFadeBitmap = createWidgetBitmap(info, finalView);                                
4072             dragView.setCrossFadeBitmap(crossFadeBitmap);                                                
4073             dragView.crossFade((int) (duration * 0.8f));                                                 
4074         } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET && external) {        
4075             scaleXY[0] = scaleXY[1] = Math.min(scaleXY[0],  scaleXY[1]);                                 
4076         }                                                                                                
4077                                                                                                          
4078         DragLayer dragLayer = mLauncher.getDragLayer();                                                  
4079         if (animationType == CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION) {                                   
4080             mLauncher.getDragLayer().animateViewIntoPosition(dragView, finalPos, 0f, 0.1f, 0.1f,         
4081                     DragLayer.ANIMATION_END_DISAPPEAR, onCompleteRunnable, duration);                    
4082         } else {                                                                                         
4083             int endStyle;                                                                                
4084             if (animationType == ANIMATE_INTO_POSITION_AND_REMAIN) {                                     
4085                 endStyle = DragLayer.ANIMATION_END_REMAIN_VISIBLE;                                       
4086             } else {                                                                                     
4087                 endStyle = DragLayer.ANIMATION_END_DISAPPEAR;;                                           
4088             }                                                                                            
4089                                                                                                          
4090             Runnable onComplete = new Runnable() {                                                       
4091                 @Override                                                                                
4092                 public void run() {                                                                      
4093                     if (finalView != null) {                                                             
4094                         finalView.setVisibility(VISIBLE);                                                
4095                     }                                                                                    
4096                     if (onCompleteRunnable != null) {                                                    
4097                         onCompleteRunnable.run();                                                        
4098                     }                                                                                    
4099                 }                                                                                        
4100             };                                                                                           
4101             dragLayer.animateViewIntoPosition(dragView, from.left, from.top, finalPos[0],                
4102                     finalPos[1], 1, 1, 1, scaleXY[0], scaleXY[1], onComplete, endStyle,                  
4103                     duration, this);                                                                     
4104         }                                                                                                
4105     }                                                                                                    
4106                                                                                                          
4107     public void setFinalTransitionTransform(CellLayout layout) {                                         
4108         if (isSwitchingState()) {                                                                        
4109             mCurrentScale = getScaleX();                                                                 
4110             setScaleX(mNewScale);                                                                        
4111             setScaleY(mNewScale);                                                                        
4112         }                                                                                                
4113     }                                                                                                    
4114     public void resetTransitionTransform(CellLayout layout) {                                            
4115         if (isSwitchingState()) {                                                                        
4116             setScaleX(mCurrentScale);                                                                    
4117             setScaleY(mCurrentScale);                                                                    
4118         }                                                                                                
4119     }                                                                                                    
4120                                                                                                          
4121     /**                                                                                                  
4122      * Return the current {@link CellLayout}, correctly picking the destination                          
4123      * screen while a scroll is in progress.                                                             
4124      */                                                                                                  
4125     public CellLayout getCurrentDropLayout() {                                                           
4126         return (CellLayout) getChildAt(getNextPage());                                                   
4127     }                                                                                                    
4128                                                                                                          
4129     /**                                                                                                  
4130      * Return the current CellInfo describing our current drag; this method exists                       
4131      * so that Launcher can sync this object with the correct info when the activity is created/         
4132      * destroyed                                                                                         
4133      *                                                                                                   
4134      */                                                                                                  
4135     public CellLayout.CellInfo getDragInfo() {                                                           
4136         return mDragInfo;                                                                                
4137     }                                                                                                    
4138                                                                                                          
4139     public int getCurrentPageOffsetFromCustomContent() {                                                 
4140         return getNextPage() - numCustomPages();                                                         
4141     }                                                                                                    
4142                                                                                                          
4143     /**                                                                                                  
4144      * Calculate the nearest cell where the given object would be dropped.                               
4145      *                                                                                                   
4146      * pixelX and pixelY should be in the coordinate system of layout                                    
4147      */                                                                                                  
4148     private int[] findNearestArea(int pixelX, int pixelY,                                                
4149             int spanX, int spanY, CellLayout layout, int[] recycle) {                                    
4150         return layout.findNearestArea(                                                                   
4151                 pixelX, pixelY, spanX, spanY, recycle);                                                  
4152     }                                                                                                    
4153                                                                                                          
4154     void setup(DragController dragController) {                                                          
4155         mSpringLoadedDragController = new SpringLoadedDragController(mLauncher);                         
4156         mDragController = dragController;                                                                
4157                                                                                                          
4158         // hardware layers on children are enabled on startup, but should be disabled until              
4159         // needed                                                                                        
4160         updateChildrenLayersEnabled(false);                                                              
4161     }                                                                                                    
4162                                                                                                          
4163     /**                                                                                                  
4164      * Called at the end of a drag which originated on the workspace.                                    
4165      */                                                                                                  
4166     public void onDropCompleted(final View target, final DragObject d,                                   
4167             final boolean isFlingToDelete, final boolean success) {                                      
4168         if (mDeferDropAfterUninstall) {                                                                  
4169             mDeferredAction = new Runnable() {                                                           
4170                 public void run() {                                                                      
4171                     onDropCompleted(target, d, isFlingToDelete, success);                                
4172                     mDeferredAction = null;                                                              
4173                 }                                                                                        
4174             };                                                                                           
4175             return;                                                                                      
4176         }                                                                                                
4177                                                                                                          
4178         boolean beingCalledAfterUninstall = mDeferredAction != null;                                     
4179                                                                                                          
4180         if (success && !(beingCalledAfterUninstall && !mUninstallSuccessful)) {                          
4181             if (target != this && mDragInfo != null) {                                                   
4182                 CellLayout parentCell = getParentCellLayoutForView(mDragInfo.cell);                      
4183                 if (parentCell != null) {                                                                
4184                     parentCell.removeView(mDragInfo.cell);                                               
4185                 } else if (LauncherAppState.isDogfoodBuild()) {                                          
4186                     throw new NullPointerException("mDragInfo.cell has null parent");                    
4187                 }                                                                                        
4188                 if (mDragInfo.cell instanceof DropTarget) {                                              
4189                     mDragController.removeDropTarget((DropTarget) mDragInfo.cell);                       
4190                 }                                                                                        
4191             }                                                                                            
4192         } else if (mDragInfo != null) {                                                                  
4193             CellLayout cellLayout;                                                                       
4194             if (mLauncher.isHotseatLayout(target)) {                                                     
4195                 cellLayout = mLauncher.getHotseat().getLayout();                                         
4196             } else {                                                                                     
4197                 cellLayout = getScreenWithId(mDragInfo.screenId);                                        
4198             }                                                                                            
4199             if (cellLayout == null && LauncherAppState.isDogfoodBuild()) {                               
4200                 throw new RuntimeException("Invalid state: cellLayout == null in "                       
4201                         + "Workspace#onDropCompleted. Please file a bug. ");                             
4202             }                                                                                            
4203             if (cellLayout != null) {                                                                    
4204                 cellLayout.onDropChild(mDragInfo.cell);                                                  
4205             }                                                                                            
4206         }                                                                                                
4207         if ((d.cancelled || (beingCalledAfterUninstall && !mUninstallSuccessful))                        
4208                 && mDragInfo.cell != null) {                                                             
4209             mDragInfo.cell.setVisibility(VISIBLE);                                                       
4210         }                                                                                                
4211         mDragOutline = null;                                                                             
4212         mDragInfo = null;                                                                                
4213     }                                                                                                    
4214                                                                                                          
4215     public void deferCompleteDropAfterUninstallActivity() {                                              
4216         mDeferDropAfterUninstall = true;                                                                 
4217     }                                                                                                    
4218                                                                                                          
4219     /// maybe move this into a smaller part                                                              
4220     public void onUninstallActivityReturned(boolean success) {                                           
4221         mDeferDropAfterUninstall = false;                                                                
4222         mUninstallSuccessful = success;                                                                  
4223         if (mDeferredAction != null) {                                                                   
4224             mDeferredAction.run();                                                                       
4225         }                                                                                                
4226     }                                                                                                    
4227                                                                                                          
4228     void updateItemLocationsInDatabase(CellLayout cl) {                                                  
4229         int count = cl.getShortcutsAndWidgets().getChildCount();                                         
4230                                                                                                          
4231         long screenId = getIdForScreen(cl);                                                              
4232         int container = Favorites.CONTAINER_DESKTOP;                                                     
4233                                                                                                          
4234         if (mLauncher.isHotseatLayout(cl)) {                                                             
4235             screenId = -1;                                                                               
4236             container = Favorites.CONTAINER_HOTSEAT;                                                     
4237         }                                                                                                
4238                                                                                                          
4239         for (int i = 0; i < count; i++) {                                                                
4240             View v = cl.getShortcutsAndWidgets().getChildAt(i);                                          
4241             ItemInfo info = (ItemInfo) v.getTag();                                                       
4242             // Null check required as the AllApps button doesn't have an item info                       
4243             if (info != null && info.requiresDbUpdate) {                                                 
4244                 info.requiresDbUpdate = false;                                                           
4245                 LauncherModel.modifyItemInDatabase(mLauncher, info, container, screenId, info.cellX,     
4246                         info.cellY, info.spanX, info.spanY);                                             
4247             }                                                                                            
4248         }                                                                                                
4249     }                                                                                                    
4250                                                                                                          
4251     ArrayList<ComponentName> getUniqueComponents(boolean stripDuplicates, ArrayList<ComponentName> duplic🔵
4252         ArrayList<ComponentName> uniqueIntents = new ArrayList<ComponentName>();                         
4253         getUniqueIntents((CellLayout) mLauncher.getHotseat().getLayout(), uniqueIntents, duplicates, fals🔵
4254         int count = getChildCount();                                                                     
4255         for (int i = 0; i < count; i++) {                                                                
4256             CellLayout cl = (CellLayout) getChildAt(i);                                                  
4257             getUniqueIntents(cl, uniqueIntents, duplicates, false);                                      
4258         }                                                                                                
4259         return uniqueIntents;                                                                            
4260     }                                                                                                    
4261                                                                                                          
4262     void getUniqueIntents(CellLayout cl, ArrayList<ComponentName> uniqueIntents,                         
4263             ArrayList<ComponentName> duplicates, boolean stripDuplicates) {                              
4264         int count = cl.getShortcutsAndWidgets().getChildCount();                                         
4265                                                                                                          
4266         ArrayList<View> children = new ArrayList<View>();                                                
4267         for (int i = 0; i < count; i++) {                                                                
4268             View v = cl.getShortcutsAndWidgets().getChildAt(i);                                          
4269             children.add(v);                                                                             
4270         }                                                                                                
4271                                                                                                          
4272         for (int i = 0; i < count; i++) {                                                                
4273             View v = children.get(i);                                                                    
4274             ItemInfo info = (ItemInfo) v.getTag();                                                       
4275             // Null check required as the AllApps button doesn't have an item info                       
4276             if (info instanceof ShortcutInfo) {                                                          
4277                 ShortcutInfo si = (ShortcutInfo) info;                                                   
4278                 ComponentName cn = si.intent.getComponent();                                             
4279                                                                                                          
4280                 Uri dataUri = si.intent.getData();                                                       
4281                 // If dataUri is not null / empty or if this component isn't one that would              
4282                 // have previously showed up in the AllApps list, then this is a widget-type             
4283                 // shortcut, so ignore it.                                                               
4284                 if (dataUri != null && !dataUri.equals(Uri.EMPTY)) {                                     
4285                     continue;                                                                            
4286                 }                                                                                        
4287                                                                                                          
4288                 if (!uniqueIntents.contains(cn)) {                                                       
4289                     uniqueIntents.add(cn);                                                               
4290                 } else {                                                                                 
4291                     if (stripDuplicates) {                                                               
4292                         cl.removeViewInLayout(v);                                                        
4293                         LauncherModel.deleteItemFromDatabase(mLauncher, si);                             
4294                     }                                                                                    
4295                     if (duplicates != null) {                                                            
4296                         duplicates.add(cn);                                                              
4297                     }                                                                                    
4298                 }                                                                                        
4299             }                                                                                            
4300             if (v instanceof FolderIcon) {                                                               
4301                 FolderIcon fi = (FolderIcon) v;                                                          
4302                 ArrayList<View> items = fi.getFolder().getItemsInReadingOrder();                         
4303                 for (int j = 0; j < items.size(); j++) {                                                 
4304                     if (items.get(j).getTag() instanceof ShortcutInfo) {                                 
4305                         ShortcutInfo si = (ShortcutInfo) items.get(j).getTag();                          
4306                         ComponentName cn = si.intent.getComponent();                                     
4307                                                                                                          
4308                         Uri dataUri = si.intent.getData();                                               
4309                         // If dataUri is not null / empty or if this component isn't one that would      
4310                         // have previously showed up in the AllApps list, then this is a widget-type     
4311                         // shortcut, so ignore it.                                                       
4312                         if (dataUri != null && !dataUri.equals(Uri.EMPTY)) {                             
4313                             continue;                                                                    
4314                         }                                                                                
4315                                                                                                          
4316                         if (!uniqueIntents.contains(cn)) {                                               
4317                             uniqueIntents.add(cn);                                                       
4318                         }  else {                                                                        
4319                             if (stripDuplicates) {                                                       
4320                                 fi.getFolderInfo().remove(si);                                           
4321                                 LauncherModel.deleteItemFromDatabase(mLauncher, si);                     
4322                             }                                                                            
4323                             if (duplicates != null) {                                                    
4324                                 duplicates.add(cn);                                                      
4325                             }                                                                            
4326                         }                                                                                
4327                     }                                                                                    
4328                 }                                                                                        
4329             }                                                                                            
4330         }                                                                                                
4331     }                                                                                                    
4332                                                                                                          
4333     void saveWorkspaceToDb() {                                                                           
4334         saveWorkspaceScreenToDb((CellLayout) mLauncher.getHotseat().getLayout());                        
4335         int count = getChildCount();                                                                     
4336         for (int i = 0; i < count; i++) {                                                                
4337             CellLayout cl = (CellLayout) getChildAt(i);                                                  
4338             saveWorkspaceScreenToDb(cl);                                                                 
4339         }                                                                                                
4340     }                                                                                                    
4341                                                                                                          
4342     void saveWorkspaceScreenToDb(CellLayout cl) {                                                        
4343         int count = cl.getShortcutsAndWidgets().getChildCount();                                         
4344                                                                                                          
4345         long screenId = getIdForScreen(cl);                                                              
4346         int container = Favorites.CONTAINER_DESKTOP;                                                     
4347                                                                                                          
4348         Hotseat hotseat = mLauncher.getHotseat();                                                        
4349         if (mLauncher.isHotseatLayout(cl)) {                                                             
4350             screenId = -1;                                                                               
4351             container = Favorites.CONTAINER_HOTSEAT;                                                     
4352         }                                                                                                
4353                                                                                                          
4354         for (int i = 0; i < count; i++) {                                                                
4355             View v = cl.getShortcutsAndWidgets().getChildAt(i);                                          
4356             ItemInfo info = (ItemInfo) v.getTag();                                                       
4357             // Null check required as the AllApps button doesn't have an item info                       
4358             if (info != null) {                                                                          
4359                 int cellX = info.cellX;                                                                  
4360                 int cellY = info.cellY;                                                                  
4361                 if (container == Favorites.CONTAINER_HOTSEAT) {                                          
4362                     cellX = hotseat.getCellXFromOrder((int) info.screenId);                              
4363                     cellY = hotseat.getCellYFromOrder((int) info.screenId);                              
4364                 }                                                                                        
4365                 LauncherModel.addItemToDatabase(mLauncher, info, container, screenId, cellX,             
4366                         cellY, false);                                                                   
4367             }                                                                                            
4368             if (v instanceof FolderIcon) {                                                               
4369                 FolderIcon fi = (FolderIcon) v;                                                          
4370                 fi.getFolder().addItemLocationsInDatabase();                                             
4371             }                                                                                            
4372         }                                                                                                
4373     }                                                                                                    
4374                                                                                                          
4375     @Override                                                                                            
4376     public float getIntrinsicIconScaleFactor() {                                                         
4377         return 1f;                                                                                       
4378     }                                                                                                    
4379                                                                                                          
4380     @Override                                                                                            
4381     public boolean supportsFlingToDelete() {                                                             
4382         return true;                                                                                     
4383     }                                                                                                    
4384                                                                                                          
4385     @Override                                                                                            
4386     public boolean supportsAppInfoDropTarget() {                                                         
4387         return false;                                                                                    
4388     }                                                                                                    
4389                                                                                                          
4390     @Override                                                                                            
4391     public boolean supportsDeleteDropTarget() {                                                          
4392         return true;                                                                                     
4393     }                                                                                                    
4394                                                                                                          
4395     @Override                                                                                            
4396     public void onFlingToDelete(DragObject d, int x, int y, PointF vec) {                                
4397         // Do nothing                                                                                    
4398     }                                                                                                    
4399                                                                                                          
4400     @Override                                                                                            
4401     public void onFlingToDeleteCompleted() {                                                             
4402         // Do nothing                                                                                    
4403     }                                                                                                    
4404                                                                                                          
4405     public boolean isDropEnabled() {                                                                     
4406         return true;                                                                                     
4407     }                                                                                                    
4408                                                                                                          
4409     @Override                                                                                            
4410     protected void onRestoreInstanceState(Parcelable state) {                                            
4411         super.onRestoreInstanceState(state);                                                             
4412         Launcher.setScreen(mCurrentPage);                                                                
4413     }                                                                                                    
4414                                                                                                          
4415     @Override                                                                                            
4416     protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {                     
4417         // We don't dispatch restoreInstanceState to our children using this code path.                  
4418         // Some pages will be restored immediately as their items are bound immediately, and             
4419         // others we will need to wait until after their items are bound.                                
4420         mSavedStates = container;                                                                        
4421     }                                                                                                    
4422                                                                                                          
4423     public void restoreInstanceStateForChild(int child) {                                                
4424         if (mSavedStates != null) {                                                                      
4425             mRestoredPages.add(child);                                                                   
4426             CellLayout cl = (CellLayout) getChildAt(child);                                              
4427             if (cl != null) {                                                                            
4428                 cl.restoreInstanceState(mSavedStates);                                                   
4429             }                                                                                            
4430         }                                                                                                
4431     }                                                                                                    
4432                                                                                                          
4433     public void restoreInstanceStateForRemainingPages() {                                                
4434         int count = getChildCount();                                                                     
4435         for (int i = 0; i < count; i++) {                                                                
4436             if (!mRestoredPages.contains(i)) {                                                           
4437                 restoreInstanceStateForChild(i);                                                         
4438             }                                                                                            
4439         }                                                                                                
4440         mRestoredPages.clear();                                                                          
4441         mSavedStates = null;                                                                             
4442     }                                                                                                    
4443                                                                                                          
4444     @Override                                                                                            
4445     public void scrollLeft() {                                                                           
4446         if (!workspaceInModalState() && !mIsSwitchingState) {                                            
4447             super.scrollLeft();                                                                          
4448         }                                                                                                
4449         Folder openFolder = getOpenFolder();                                                             
4450         if (openFolder != null) {                                                                        
4451             openFolder.completeDragExit();                                                               
4452         }                                                                                                
4453     }                                                                                                    
4454                                                                                                          
4455     @Override                                                                                            
4456     public void scrollRight() {                                                                          
4457         if (!workspaceInModalState() && !mIsSwitchingState) {                                            
4458             super.scrollRight();                                                                         
4459         }                                                                                                
4460         Folder openFolder = getOpenFolder();                                                             
4461         if (openFolder != null) {                                                                        
4462             openFolder.completeDragExit();                                                               
4463         }                                                                                                
4464     }                                                                                                    
4465                                                                                                          
4466     @Override                                                                                            
4467     public boolean onEnterScrollArea(int x, int y, int direction) {                                      
4468         // Ignore the scroll area if we are dragging over the hot seat                                   
4469         boolean isPortrait = !LauncherAppState.isScreenLandscape(getContext());                          
4470         if (mLauncher.getHotseat() != null && isPortrait) {                                              
4471             Rect r = new Rect();                                                                         
4472             mLauncher.getHotseat().getHitRect(r);                                                        
4473             if (r.contains(x, y)) {                                                                      
4474                 return false;                                                                            
4475             }                                                                                            
4476         }                                                                                                
4477                                                                                                          
4478         boolean result = false;                                                                          
4479         if (!workspaceInModalState() && !mIsSwitchingState && getOpenFolder() == null) {                 
4480             mInScrollArea = true;                                                                        
4481                                                                                                          
4482             final int page = getNextPage() +                                                             
4483                        (direction == DragController.SCROLL_LEFT ? -1 : 1);                               
4484             // We always want to exit the current layout to ensure parity of enter / exit                
4485             setCurrentDropLayout(null);                                                                  
4486                                                                                                          
4487             if (0 <= page && page < getChildCount()) {                                                   
4488                 // Ensure that we are not dragging over to the custom content screen                     
4489                 if (getScreenIdForPageIndex(page) == CUSTOM_CONTENT_SCREEN_ID) {                         
4490                     return false;                                                                        
4491                 }                                                                                        
4492                                                                                                          
4493                 CellLayout layout = (CellLayout) getChildAt(page);                                       
4494                 setCurrentDragOverlappingLayout(layout);                                                 
4495                                                                                                          
4496                 // Workspace is responsible for drawing the edge glow on adjacent pages,                 
4497                 // so we need to redraw the workspace when this may have changed.                        
4498                 invalidate();                                                                            
4499                 result = true;                                                                           
4500             }                                                                                            
4501         }                                                                                                
4502         return result;                                                                                   
4503     }                                                                                                    
4504                                                                                                          
4505     @Override                                                                                            
4506     public boolean onExitScrollArea() {                                                                  
4507         boolean result = false;                                                                          
4508         if (mInScrollArea) {                                                                             
4509             invalidate();                                                                                
4510             CellLayout layout = getCurrentDropLayout();                                                  
4511             setCurrentDropLayout(layout);                                                                
4512             setCurrentDragOverlappingLayout(layout);                                                     
4513                                                                                                          
4514             result = true;                                                                               
4515             mInScrollArea = false;                                                                       
4516         }                                                                                                
4517         return result;                                                                                   
4518     }                                                                                                    
4519                                                                                                          
4520     private void onResetScrollArea() {                                                                   
4521         setCurrentDragOverlappingLayout(null);                                                           
4522         mInScrollArea = false;                                                                           
4523     }                                                                                                    
4524                                                                                                          
4525     /**                                                                                                  
4526      * Returns a specific CellLayout                                                                     
4527      */                                                                                                  
4528     CellLayout getParentCellLayoutForView(View v) {                                                      
4529         ArrayList<CellLayout> layouts = getWorkspaceAndHotseatCellLayouts();                             
4530         for (CellLayout layout : layouts) {                                                              
4531             if (layout.getShortcutsAndWidgets().indexOfChild(v) > -1) {                                  
4532                 return layout;                                                                           
4533             }                                                                                            
4534         }                                                                                                
4535         return null;                                                                                     
4536     }                                                                                                    
4537                                                                                                          
4538     /**                                                                                                  
4539      * Returns a list of all the CellLayouts in the workspace.                                           
4540      */                                                                                                  
4541     ArrayList<CellLayout> getWorkspaceAndHotseatCellLayouts() {                                          
4542         ArrayList<CellLayout> layouts = new ArrayList<CellLayout>();                                     
4543         int screenCount = getChildCount();                                                               
4544         for (int screen = 0; screen < screenCount; screen++) {                                           
4545             layouts.add(((CellLayout) getChildAt(screen)));                                              
4546         }                                                                                                
4547         if (mLauncher.getHotseat() != null) {                                                            
4548             layouts.add(mLauncher.getHotseat().getLayout());                                             
4549         }                                                                                                
4550         return layouts;                                                                                  
4551     }                                                                                                    
4552                                                                                                          
4553     /**                                                                                                  
4554      * We should only use this to search for specific children.  Do not use this method to modify        
4555      * ShortcutsAndWidgetsContainer directly. Includes ShortcutAndWidgetContainers from                  
4556      * the hotseat and workspace pages                                                                   
4557      */                                                                                                  
4558     ArrayList<ShortcutAndWidgetContainer> getAllShortcutAndWidgetContainers() {                          
4559         ArrayList<ShortcutAndWidgetContainer> childrenLayouts =                                          
4560                 new ArrayList<ShortcutAndWidgetContainer>();                                             
4561         int screenCount = getChildCount();                                                               
4562         for (int screen = 0; screen < screenCount; screen++) {                                           
4563             childrenLayouts.add(((CellLayout) getChildAt(screen)).getShortcutsAndWidgets());             
4564         }                                                                                                
4565         if (mLauncher.getHotseat() != null) {                                                            
4566             childrenLayouts.add(mLauncher.getHotseat().getLayout().getShortcutsAndWidgets());            
4567         }                                                                                                
4568         return childrenLayouts;                                                                          
4569     }                                                                                                    
4570                                                                                                          
4571     public Folder getFolderForTag(final Object tag) {                                                    
4572         return (Folder) getFirstMatch(new ItemOperator() {                                               
4573                                                                                                          
4574             @Override                                                                                    
4575             public boolean evaluate(ItemInfo info, View v, View parent) {                                
4576                 return (v instanceof Folder) && (((Folder) v).getInfo() == tag)                          
4577                         && ((Folder) v).getInfo().opened;                                                
4578             }                                                                                            
4579         });                                                                                              
4580     }                                                                                                    
4581                                                                                                          
4582     public View getViewForTag(final Object tag) {                                                        
4583         return getFirstMatch(new ItemOperator() {                                                        
4584                                                                                                          
4585             @Override                                                                                    
4586             public boolean evaluate(ItemInfo info, View v, View parent) {                                
4587                 return info == tag;                                                                      
4588             }                                                                                            
4589         });                                                                                              
4590     }                                                                                                    
4591                                                                                                          
4592     public LauncherAppWidgetHostView getWidgetForAppWidgetId(final int appWidgetId) {                    
4593         return (LauncherAppWidgetHostView) getFirstMatch(new ItemOperator() {                            
4594                                                                                                          
4595             @Override                                                                                    
4596             public boolean evaluate(ItemInfo info, View v, View parent) {                                
4597                 return (info instanceof LauncherAppWidgetInfo) &&                                        
4598                         ((LauncherAppWidgetInfo) info).appWidgetId == appWidgetId;                       
4599             }                                                                                            
4600         });                                                                                              
4601     }                                                                                                    
4602                                                                                                          
4603     private View getFirstMatch(final ItemOperator operator) {                                            
4604         final View[] value = new View[1];                                                                
4605         mapOverItems(MAP_NO_RECURSE, new ItemOperator() {                                                
4606             @Override                                                                                    
4607             public boolean evaluate(ItemInfo info, View v, View parent) {                                
4608                 if (operator.evaluate(info, v, parent)) {                                                
4609                     value[0] = v;                                                                        
4610                     return true;                                                                         
4611                 }                                                                                        
4612                 return false;                                                                            
4613             }                                                                                            
4614         });                                                                                              
4615         return value[0];                                                                                 
4616     }                                                                                                    
4617                                                                                                          
4618     void clearDropTargets() {                                                                            
4619         mapOverItems(MAP_NO_RECURSE, new ItemOperator() {                                                
4620             @Override                                                                                    
4621             public boolean evaluate(ItemInfo info, View v, View parent) {                                
4622                 if (v instanceof DropTarget) {                                                           
4623                     mDragController.removeDropTarget((DropTarget) v);                                    
4624                 }                                                                                        
4625                 // not done, process all the shortcuts                                                   
4626                 return false;                                                                            
4627             }                                                                                            
4628         });                                                                                              
4629     }                                                                                                    
4630                                                                                                          
4631     // Removes ALL items that match a given package name, this is usually called when a package          
4632     // has been removed and we want to remove all components (widgets, shortcuts, apps) that             
4633     // belong to that package.                                                                           
4634     void removeItemsByPackageName(final ArrayList<String> packages, final UserHandleCompat user) {       
4635         final HashSet<String> packageNames = new HashSet<String>();                                      
4636         packageNames.addAll(packages);                                                                   
4637                                                                                                          
4638         // Filter out all the ItemInfos that this is going to affect                                     
4639         final HashSet<ItemInfo> infos = new HashSet<ItemInfo>();                                         
4640         final HashSet<ComponentName> cns = new HashSet<ComponentName>();                                 
4641         ArrayList<CellLayout> cellLayouts = getWorkspaceAndHotseatCellLayouts();                         
4642         for (CellLayout layoutParent : cellLayouts) {                                                    
4643             ViewGroup layout = layoutParent.getShortcutsAndWidgets();                                    
4644             int childCount = layout.getChildCount();                                                     
4645             for (int i = 0; i < childCount; ++i) {                                                       
4646                 View view = layout.getChildAt(i);                                                        
4647                 infos.add((ItemInfo) view.getTag());                                                     
4648             }                                                                                            
4649         }                                                                                                
4650         LauncherModel.ItemInfoFilter filter = new LauncherModel.ItemInfoFilter() {                       
4651             @Override                                                                                    
4652             public boolean filterItem(ItemInfo parent, ItemInfo info,                                    
4653                                       ComponentName cn) {                                                
4654                 if (packageNames.contains(cn.getPackageName())                                           
4655                         && info.user.equals(user)) {                                                     
4656                     cns.add(cn);                                                                         
4657                     return true;                                                                         
4658                 }                                                                                        
4659                 return false;                                                                            
4660             }                                                                                            
4661         };                                                                                               
4662         LauncherModel.filterItemInfos(infos, filter);                                                    
4663                                                                                                          
4664         // Remove the affected components                                                                
4665         removeItemsByComponentName(cns, user);                                                           
4666     }                                                                                                    
4667                                                                                                          
4668     // Removes items that match the application info specified, when applications are removed            
4669     // as a part of an update, this is called to ensure that other widgets and application               
4670     // shortcuts are not removed.                                                                        
4671     void removeItemsByApplicationInfo(final ArrayList<AppInfo> appInfos, UserHandleCompat user) {        
4672         // Just create a hash table of all the specific components that this will affect                 
4673         HashSet<ComponentName> cns = new HashSet<ComponentName>();                                       
4674         for (AppInfo info : appInfos) {                                                                  
4675             cns.add(info.componentName);                                                                 
4676         }                                                                                                
4677                                                                                                          
4678         // Remove all the things                                                                         
4679         removeItemsByComponentName(cns, user);                                                           
4680     }                                                                                                    
4681                                                                                                          
4682     void removeItemsByComponentName(final HashSet<ComponentName> componentNames,                         
4683             final UserHandleCompat user) {                                                               
4684         ArrayList<CellLayout> cellLayouts = getWorkspaceAndHotseatCellLayouts();                         
4685         for (final CellLayout layoutParent: cellLayouts) {                                               
4686             final ViewGroup layout = layoutParent.getShortcutsAndWidgets();                              
4687                                                                                                          
4688             final HashMap<ItemInfo, View> children = new HashMap<ItemInfo, View>();                      
4689             for (int j = 0; j < layout.getChildCount(); j++) {                                           
4690                 final View view = layout.getChildAt(j);                                                  
4691                 children.put((ItemInfo) view.getTag(), view);                                            
4692             }                                                                                            
4693                                                                                                          
4694             final ArrayList<View> childrenToRemove = new ArrayList<View>();                              
4695             final HashMap<FolderInfo, ArrayList<ShortcutInfo>> folderAppsToRemove =                      
4696                     new HashMap<FolderInfo, ArrayList<ShortcutInfo>>();                                  
4697             LauncherModel.ItemInfoFilter filter = new LauncherModel.ItemInfoFilter() {                   
4698                 @Override                                                                                
4699                 public boolean filterItem(ItemInfo parent, ItemInfo info,                                
4700                                           ComponentName cn) {                                            
4701                     if (parent instanceof FolderInfo) {                                                  
4702                         if (componentNames.contains(cn) && info.user.equals(user)) {                     
4703                             FolderInfo folder = (FolderInfo) parent;                                     
4704                             ArrayList<ShortcutInfo> appsToRemove;                                        
4705                             if (folderAppsToRemove.containsKey(folder)) {                                
4706                                 appsToRemove = folderAppsToRemove.get(folder);                           
4707                             } else {                                                                     
4708                                 appsToRemove = new ArrayList<ShortcutInfo>();                            
4709                                 folderAppsToRemove.put(folder, appsToRemove);                            
4710                             }                                                                            
4711                             appsToRemove.add((ShortcutInfo) info);                                       
4712                             return true;                                                                 
4713                         }                                                                                
4714                     } else {                                                                             
4715                         if (componentNames.contains(cn) && info.user.equals(user)) {                     
4716                             childrenToRemove.add(children.get(info));                                    
4717                             return true;                                                                 
4718                         }                                                                                
4719                     }                                                                                    
4720                     return false;                                                                        
4721                 }                                                                                        
4722             };                                                                                           
4723             LauncherModel.filterItemInfos(children.keySet(), filter);                                    
4724                                                                                                          
4725             // Remove all the apps from their folders                                                    
4726             for (FolderInfo folder : folderAppsToRemove.keySet()) {                                      
4727                 ArrayList<ShortcutInfo> appsToRemove = folderAppsToRemove.get(folder);                   
4728                 for (ShortcutInfo info : appsToRemove) {                                                 
4729                     folder.remove(info);                                                                 
4730                 }                                                                                        
4731             }                                                                                            
4732                                                                                                          
4733             // Remove all the other children                                                             
4734             for (View child : childrenToRemove) {                                                        
4735                 // Note: We can not remove the view directly from CellLayoutChildren as this             
4736                 // does not re-mark the spaces as unoccupied.                                            
4737                 layoutParent.removeViewInLayout(child);                                                  
4738                 if (child instanceof DropTarget) {                                                       
4739                     mDragController.removeDropTarget((DropTarget) child);                                
4740                 }                                                                                        
4741             }                                                                                            
4742                                                                                                          
4743             if (childrenToRemove.size() > 0) {                                                           
4744                 layout.requestLayout();                                                                  
4745                 layout.invalidate();                                                                     
4746             }                                                                                            
4747         }                                                                                                
4748                                                                                                          
4749         // Strip all the empty screens                                                                   
4750         stripEmptyScreens();                                                                             
4751     }                                                                                                    
4752                                                                                                          
4753 <<<<<<< GitAnalyzerPlus_ours                                                                             
4754     interface ItemOperator {                                                                             
4755         /**                                                                                              
4756          * Process the next itemInfo, possibly with side-effect on {@link ItemOperator#value}.           
4757          *                                                                                               
4758          * @param info info for the shortcut                                                             
4759          * @param view view for the shortcut                                                             
4760          * @param parent containing folder, or null                                                      
4761          * @return true if done, false to continue the map                                               
4762          */                                                                                              
4763         public boolean evaluate(ItemInfo info, View view, View parent);                                  
4764 ||||||| GitAnalyzerPlus_base                                                                             
4765                                                                                                          
4766     private void updateShortcut(HashMap<ComponentName, AppInfo> appsMap, ItemInfo info,                  
4767                                 View child) {                                                            
4768         ComponentName cn = info.getIntent().getComponent();                                              
4769         if (info.getRestoredIntent() != null) {                                                          
4770             cn = info.getRestoredIntent().getComponent();                                                
4771         }                                                                                                
4772         if (cn != null) {                                                                                
4773             AppInfo appInfo = appsMap.get(cn);                                                           
4774             if ((appInfo != null) && LauncherModel.isShortcutInfoUpdateable(info)) {                     
4775                 ShortcutInfo shortcutInfo = (ShortcutInfo) info;                                         
4776                 BubbleTextView shortcut = (BubbleTextView) child;                                        
4777                 shortcutInfo.restore();                                                                  
4778                 shortcutInfo.updateIcon(mIconCache);                                                     
4779                 shortcutInfo.title = appInfo.title.toString();                                           
4780                 shortcut.applyFromShortcutInfo(shortcutInfo, mIconCache);                                
4781             }                                                                                            
4782         }                                                                                                
4783     }                                                                                                    
4784                                                                                                          
4785     void updateShortcuts(ArrayList<AppInfo> apps) {                                                      
4786         // Create a map of the apps to test against                                                      
4787         final HashMap<ComponentName, AppInfo> appsMap = new HashMap<ComponentName, AppInfo>();           
4788         for (AppInfo ai : apps) {                                                                        
4789             appsMap.put(ai.componentName, ai);                                                           
4790         }                                                                                                
4791                                                                                                          
4792         ArrayList<ShortcutAndWidgetContainer> childrenLayouts = getAllShortcutAndWidgetContainers();     
4793         for (ShortcutAndWidgetContainer layout: childrenLayouts) {                                       
4794             // Update all the children shortcuts                                                         
4795             final HashMap<ItemInfo, View> children = new HashMap<ItemInfo, View>();                      
4796             for (int j = 0; j < layout.getChildCount(); j++) {                                           
4797                 View v = layout.getChildAt(j);                                                           
4798                 ItemInfo info = (ItemInfo) v.getTag();                                                   
4799                 if (info instanceof FolderInfo && v instanceof FolderIcon) {                             
4800                     FolderIcon folder = (FolderIcon) v;                                                  
4801                     ArrayList<View> folderChildren = folder.getFolder().getItemsInReadingOrder();        
4802                     for (View fv : folderChildren) {                                                     
4803                         info = (ItemInfo) fv.getTag();                                                   
4804                         updateShortcut(appsMap, info, fv);                                               
4805                     }                                                                                    
4806                     folder.invalidate();                                                                 
4807                 } else if (info instanceof ShortcutInfo) {                                               
4808                     updateShortcut(appsMap, info, v);                                                    
4809                 }                                                                                        
4810             }                                                                                            
4811         }                                                                                                
4812     }                                                                                                    
4813                                                                                                          
4814     private void moveToScreen(int page, boolean animate) {                                               
4815         if (!isSmall()) {                                                                                
4816             if (animate) {                                                                               
4817                 snapToPage(page);                                                                        
4818             } else {                                                                                     
4819                 setCurrentPage(page);                                                                    
4820             }                                                                                            
4821         }                                                                                                
4822         View child = getChildAt(page);                                                                   
4823         if (child != null) {                                                                             
4824             child.requestFocus();                                                                        
4825         }                                                                                                
4826     }                                                                                                    
4827                                                                                                          
4828     void moveToDefaultScreen(boolean animate) {                                                          
4829         moveToScreen(mDefaultPage, animate);                                                             
4830     }                                                                                                    
4831                                                                                                          
4832     void moveToCustomContentScreen(boolean animate) {                                                    
4833         if (hasCustomContent()) {                                                                        
4834             int ccIndex = getPageIndexForScreenId(CUSTOM_CONTENT_SCREEN_ID);                             
4835             if (animate) {                                                                               
4836                 snapToPage(ccIndex);                                                                     
4837             } else {                                                                                     
4838                 setCurrentPage(ccIndex);                                                                 
4839             }                                                                                            
4840             View child = getChildAt(ccIndex);                                                            
4841             if (child != null) {                                                                         
4842                 child.requestFocus();                                                                    
4843             }                                                                                            
4844          }                                                                                               
4845         exitWidgetResizeMode();                                                                          
4846     }                                                                                                    
4847                                                                                                          
4848     @Override                                                                                            
4849     protected PageIndicator.PageMarkerResources getPageIndicatorMarker(int pageIndex) {                  
4850         long screenId = getScreenIdForPageIndex(pageIndex);                                              
4851         if (screenId == EXTRA_EMPTY_SCREEN_ID) {                                                         
4852             int count = mScreenOrder.size() - numCustomPages();                                          
4853             if (count > 1) {                                                                             
4854                 return new PageIndicator.PageMarkerResources(R.drawable.ic_pageindicator_current,        
4855                         R.drawable.ic_pageindicator_add);                                                
4856             }                                                                                            
4857         }                                                                                                
4858                                                                                                          
4859         return super.getPageIndicatorMarker(pageIndex);                                                  
4860     }                                                                                                    
4861                                                                                                          
4862     @Override                                                                                            
4863     public void syncPages() {                                                                            
4864     }                                                                                                    
4865                                                                                                          
4866     @Override                                                                                            
4867     public void syncPageItems(int page, boolean immediate) {                                             
4868     }                                                                                                    
4869                                                                                                          
4870     protected String getPageIndicatorDescription() {                                                     
4871         String settings = getResources().getString(R.string.settings_button_text);                       
4872         return getCurrentPageDescription() + ", " + settings;                                            
4873     }                                                                                                    
4874                                                                                                          
4875     protected String getCurrentPageDescription() {                                                       
4876         int page = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage;                               
4877         int delta = numCustomPages();                                                                    
4878         if (hasCustomContent() && getNextPage() == 0) {                                                  
4879             return mCustomContentDescription;                                                            
4880         }                                                                                                
4881         return String.format(getContext().getString(R.string.workspace_scroll_format),                   
4882                 page + 1 - delta, getChildCount() - delta);                                              
4883     }                                                                                                    
4884                                                                                                          
4885     public void getLocationInDragLayer(int[] loc) {                                                      
4886         mLauncher.getDragLayer().getLocationInDragLayer(this, loc);                                      
4887     }                                                                                                    
4888 }                                                                                                        
4889 =======                                                                                                  
4890     private void updateShortcut(HashMap<ComponentName, AppInfo> appsMap, ItemInfo info,                  
4891                                 View child) {                                                            
4892         ComponentName cn = info.getIntent().getComponent();                                              
4893         if (cn != null) {                                                                                
4894             AppInfo appInfo = appsMap.get(info.getIntent().getComponent());                              
4895             if ((appInfo != null) && LauncherModel.isShortcutInfoUpdateable(info)) {                     
4896                 ShortcutInfo shortcutInfo = (ShortcutInfo) info;                                         
4897                 BubbleTextView shortcut = (BubbleTextView) child;                                        
4898                 shortcutInfo.updateIcon(mIconCache);                                                     
4899                 shortcutInfo.title = appInfo.title.toString();                                           
4900                 shortcut.applyFromShortcutInfo(shortcutInfo, mIconCache);                                
4901             }                                                                                            
4902         }                                                                                                
4903 >>>>>>> GitAnalyzerPlus_theirs                                                                           
4904     }                                                                                                    
4905                                                                                                          
4906     /**                                                                                                  
4907      * Map the operator over the shortcuts and widgets, return the first-non-null value.                 
4908      *                                                                                                   
4909      * @param recurse true: iterate over folder children. false: op get the folders themselves.          
4910      * @param op the operator to map over the shortcuts                                                  
4911      */                                                                                                  
4912     void mapOverItems(boolean recurse, ItemOperator op) {                                                
4913         ArrayList<ShortcutAndWidgetContainer> containers = getAllShortcutAndWidgetContainers();          
4914         final int containerCount = containers.size();                                                    
4915         for (int containerIdx = 0; containerIdx < containerCount; containerIdx++) {                      
4916             ShortcutAndWidgetContainer container = containers.get(containerIdx);                         
4917             // map over all the shortcuts on the workspace                                               
4918             final int itemCount = container.getChildCount();                                             
4919             for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) {                                      
4920                 View item = container.getChildAt(itemIdx);                                               
4921                 ItemInfo info = (ItemInfo) item.getTag();                                                
4922                 if (recurse && info instanceof FolderInfo && item instanceof FolderIcon) {               
4923                     FolderIcon folder = (FolderIcon) item;                                               
4924                     ArrayList<View> folderChildren = folder.getFolder().getItemsInReadingOrder();        
4925                     // map over all the children in the folder                                           
4926                     final int childCount = folderChildren.size();                                        
4927                     for (int childIdx = 0; childIdx < childCount; childIdx++) {                          
4928                         View child = folderChildren.get(childIdx);                                       
4929                         info = (ItemInfo) child.getTag();                                                
4930                         if (op.evaluate(info, child, folder)) {                                          
4931                             return;                                                                      
4932                         }                                                                                
4933                     }                                                                                    
4934                 } else {                                                                                 
4935                     if (op.evaluate(info, item, null)) {                                                 
4936                         return;                                                                          
4937                     }                                                                                    
4938                 }                                                                                        
4939             }                                                                                            
4940         }                                                                                                
4941     }                                                                                                    
4942                                                                                                          
4943     void updateShortcutsAndWidgets(ArrayList<AppInfo> apps) {                                            
4944         // Break the appinfo list per user                                                               
4945         final HashMap<UserHandleCompat, ArrayList<AppInfo>> appsPerUser =                                
4946                 new HashMap<UserHandleCompat, ArrayList<AppInfo>>();                                     
4947         for (AppInfo info : apps) {                                                                      
4948             ArrayList<AppInfo> filtered = appsPerUser.get(info.user);                                    
4949             if (filtered == null) {                                                                      
4950                 filtered = new ArrayList<AppInfo>();                                                     
4951                 appsPerUser.put(info.user, filtered);                                                    
4952             }                                                                                            
4953             filtered.add(info);                                                                          
4954         }                                                                                                
4955                                                                                                          
4956         for (Map.Entry<UserHandleCompat, ArrayList<AppInfo>> entry : appsPerUser.entrySet()) {           
4957             updateShortcutsAndWidgetsPerUser(entry.getValue(), entry.getKey());                          
4958         }                                                                                                
4959     }                                                                                                    
4960                                                                                                          
4961     private void updateShortcutsAndWidgetsPerUser(ArrayList<AppInfo> apps,                               
4962             final UserHandleCompat user) {                                                               
4963         // Create a map of the apps to test against                                                      
4964         final HashMap<ComponentName, AppInfo> appsMap = new HashMap<ComponentName, AppInfo>();           
4965         final HashSet<String> pkgNames = new HashSet<String>();                                          
4966         for (AppInfo ai : apps) {                                                                        
4967             appsMap.put(ai.componentName, ai);                                                           
4968             pkgNames.add(ai.componentName.getPackageName());                                             
4969         }                                                                                                
4970         final HashSet<ComponentName> iconsToRemove = new HashSet<ComponentName>();                       
4971                                                                                                          
4972         mapOverItems(MAP_RECURSE, new ItemOperator() {                                                   
4973             @Override                                                                                    
4974             public boolean evaluate(ItemInfo info, View v, View parent) {                                
4975                 if (info instanceof ShortcutInfo && v instanceof BubbleTextView) {                       
4976                     ShortcutInfo shortcutInfo = (ShortcutInfo) info;                                     
4977                     ComponentName cn = shortcutInfo.getTargetComponent();                                
4978                     AppInfo appInfo = appsMap.get(cn);                                                   
4979                     if (user.equals(shortcutInfo.user) && cn != null                                     
4980                             && LauncherModel.isShortcutInfoUpdateable(info)                              
4981                             && pkgNames.contains(cn.getPackageName())) {                                 
4982                         boolean promiseStateChanged = false;                                             
4983                         boolean infoUpdated = false;                                                     
4984                         if (shortcutInfo.isPromise()) {                                                  
4985                             if (shortcutInfo.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {         
4986                                 // Auto install icon                                                     
4987                                 PackageManager pm = getContext().getPackageManager();                    
4988                                 ResolveInfo matched = pm.resolveActivity(                                
4989                                         new Intent(Intent.ACTION_MAIN)                                   
4990                                         .setComponent(cn).addCategory(Intent.CATEGORY_LAUNCHER),         
4991                                         PackageManager.MATCH_DEFAULT_ONLY);                              
4992                                 if (matched == null) {                                                   
4993                                     // Try to find the best match activity.                              
4994                                     Intent intent = pm.getLaunchIntentForPackage(                        
4995                                             cn.getPackageName());                                        
4996                                     if (intent != null) {                                                
4997                                         cn = intent.getComponent();                                      
4998                                         appInfo = appsMap.get(cn);                                       
4999                                     }                                                                    
5000                                                                                                          
5001                                     if ((intent == null) || (appsMap == null)) {                         
5002                                         // Could not find a default activity. Remove this item.          
5003                                         iconsToRemove.add(shortcutInfo.getTargetComponent());            
5004                                                                                                          
5005                                         // process next shortcut.                                        
5006                                         return false;                                                    
5007                                     }                                                                    
5008                                     shortcutInfo.promisedIntent = intent;                                
5009                                 }                                                                        
5010                             }                                                                            
5011                                                                                                          
5012                             // Restore the shortcut.                                                     
5013                             shortcutInfo.intent = shortcutInfo.promisedIntent;                           
5014                             shortcutInfo.promisedIntent = null;                                          
5015                             shortcutInfo.status &= ~ShortcutInfo.FLAG_RESTORED_ICON                      
5016                                     & ~ShortcutInfo.FLAG_AUTOINTALL_ICON                                 
5017                                     & ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;                         
5018                                                                                                          
5019                             promiseStateChanged = true;                                                  
5020                             infoUpdated = true;                                                          
5021                             shortcutInfo.updateIcon(mIconCache);                                         
5022                             LauncherModel.updateItemInDatabase(getContext(), shortcutInfo);              
5023                         }                                                                                
5024                                                                                                          
5025                                                                                                          
5026                         if (appInfo != null) {                                                           
5027                             shortcutInfo.updateIcon(mIconCache);                                         
5028                             shortcutInfo.title = appInfo.title.toString();                               
5029                             shortcutInfo.contentDescription = appInfo.contentDescription;                
5030                             infoUpdated = true;                                                          
5031                         }                                                                                
5032                                                                                                          
5033                         if (infoUpdated) {                                                               
5034                             BubbleTextView shortcut = (BubbleTextView) v;                                
5035                             shortcut.applyFromShortcutInfo(shortcutInfo,                                 
5036                                     mIconCache, true, promiseStateChanged);                              
5037                                                                                                          
5038                             if (parent != null) {                                                        
5039                                 parent.invalidate();                                                     
5040                             }                                                                            
5041                         }                                                                                
5042                     }                                                                                    
5043                 }                                                                                        
5044                 // process all the shortcuts                                                             
5045                 return false;                                                                            
5046             }                                                                                            
5047         });                                                                                              
5048                                                                                                          
5049         if (!iconsToRemove.isEmpty()) {                                                                  
5050             removeItemsByComponentName(iconsToRemove, user);                                             
5051         }                                                                                                
5052         if (user.equals(UserHandleCompat.myUserHandle())) {                                              
5053             restorePendingWidgets(pkgNames);                                                             
5054         }                                                                                                
5055     }                                                                                                    
5056                                                                                                          
5057     public void removeAbandonedPromise(String packageName, UserHandleCompat user) {                      
5058         ArrayList<String> packages = new ArrayList<String>(1);                                           
5059         packages.add(packageName);                                                                       
5060         LauncherModel.deletePackageFromDatabase(mLauncher, packageName, user);                           
5061         removeItemsByPackageName(packages, user);                                                        
5062     }                                                                                                    
5063                                                                                                          
5064     public void updatePackageBadge(final String packageName, final UserHandleCompat user) {              
5065         mapOverItems(MAP_RECURSE, new ItemOperator() {                                                   
5066             @Override                                                                                    
5067             public boolean evaluate(ItemInfo info, View v, View parent) {                                
5068                 if (info instanceof ShortcutInfo && v instanceof BubbleTextView) {                       
5069                     ShortcutInfo shortcutInfo = (ShortcutInfo) info;                                     
5070                     ComponentName cn = shortcutInfo.getTargetComponent();                                
5071                     if (user.equals(shortcutInfo.user) && cn != null                                     
5072                             && shortcutInfo.isPromise()                                                  
5073                             && packageName.equals(cn.getPackageName())) {                                
5074                         if (shortcutInfo.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {             
5075                             // For auto install apps update the icon as well as label.                   
5076                             mIconCache.getTitleAndIcon(shortcutInfo,                                     
5077                                     shortcutInfo.promisedIntent, user, true);                            
5078                         } else {                                                                         
5079                             // Only update the icon for restored apps.                                   
5080                             shortcutInfo.updateIcon(mIconCache);                                         
5081                         }                                                                                
5082                         BubbleTextView shortcut = (BubbleTextView) v;                                    
5083                         shortcut.applyFromShortcutInfo(shortcutInfo, mIconCache, true, false);           
5084                                                                                                          
5085                         if (parent != null) {                                                            
5086                             parent.invalidate();                                                         
5087                         }                                                                                
5088                     }                                                                                    
5089                 }                                                                                        
5090                 // process all the shortcuts                                                             
5091                 return false;                                                                            
5092             }                                                                                            
5093         });                                                                                              
5094     }                                                                                                    
5095                                                                                                          
5096     public void updatePackageState(ArrayList<PackageInstallInfo> installInfos) {                         
5097         HashSet<String> completedPackages = new HashSet<String>();                                       
5098                                                                                                          
5099         for (final PackageInstallInfo installInfo : installInfos) {                                      
5100             mapOverItems(MAP_RECURSE, new ItemOperator() {                                               
5101                 @Override                                                                                
5102                 public boolean evaluate(ItemInfo info, View v, View parent) {                            
5103                     if (info instanceof ShortcutInfo && v instanceof BubbleTextView) {                   
5104                         ShortcutInfo si = (ShortcutInfo) info;                                           
5105                         ComponentName cn = si.getTargetComponent();                                      
5106                         if (si.isPromise() && (cn != null)                                               
5107                                 && installInfo.packageName.equals(cn.getPackageName())) {                
5108                             si.setInstallProgress(installInfo.progress);                                 
5109                             if (installInfo.state == PackageInstallerCompat.STATUS_FAILED) {             
5110                                 // Mark this info as broken.                                             
5111                                 si.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;                  
5112                             }                                                                            
5113                             ((BubbleTextView)v).applyState(false);                                       
5114                         }                                                                                
5115                     } else if (v instanceof PendingAppWidgetHostView                                     
5116                             && info instanceof LauncherAppWidgetInfo                                     
5117                             && ((LauncherAppWidgetInfo) info).providerName.getPackageName()              
5118                                 .equals(installInfo.packageName)) {                                      
5119                         ((LauncherAppWidgetInfo) info).installProgress = installInfo.progress;           
5120                         ((PendingAppWidgetHostView) v).applyState();                                     
5121                     }                                                                                    
5122                                                                                                          
5123                     // process all the shortcuts                                                         
5124                     return false;                                                                        
5125                 }                                                                                        
5126             });                                                                                          
5127                                                                                                          
5128             if (installInfo.state == PackageInstallerCompat.STATUS_INSTALLED) {                          
5129                 completedPackages.add(installInfo.packageName);                                          
5130             }                                                                                            
5131         }                                                                                                
5132                                                                                                          
5133         // Note that package states are sent only for myUser                                             
5134         if (!completedPackages.isEmpty()) {                                                              
5135             restorePendingWidgets(completedPackages);                                                    
5136         }                                                                                                
5137     }                                                                                                    
5138                                                                                                          
5139     private void restorePendingWidgets(final Set<String> installedPackaged) {                            
5140         final ArrayList<LauncherAppWidgetInfo> changedInfo = new ArrayList<LauncherAppWidgetInfo>();     
5141                                                                                                          
5142         // Iterate non recursively as widgets can't be inside a folder.                                  
5143         mapOverItems(MAP_NO_RECURSE, new ItemOperator() {                                                
5144                                                                                                          
5145             @Override                                                                                    
5146             public boolean evaluate(ItemInfo info, View v, View parent) {                                
5147                 if (info instanceof LauncherAppWidgetInfo) {                                             
5148                     LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info;                     
5149                     if (widgetInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)         
5150                             && installedPackaged.contains(widgetInfo.providerName.getPackageName())) {   
5151                                                                                                          
5152                         changedInfo.add(widgetInfo);                                                     
5153                                                                                                          
5154                         // Remove the provider not ready flag                                            
5155                         widgetInfo.restoreStatus &= ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;      
5156                         LauncherModel.updateItemInDatabase(getContext(), widgetInfo);                    
5157                     }                                                                                    
5158                 }                                                                                        
5159                 // process all the widget                                                                
5160                 return false;                                                                            
5161             }                                                                                            
5162         });                                                                                              
5163         if (!changedInfo.isEmpty()) {                                                                    
5164             DeferredWidgetRefresh widgetRefresh = new DeferredWidgetRefresh(changedInfo,                 
5165                     mLauncher.getAppWidgetHost());                                                       
5166             if (LauncherModel.findAppWidgetProviderInfoWithComponent(getContext(),                       
5167                     changedInfo.get(0).providerName) != null) {                                          
5168                 // Re-inflate the widgets which have changed status                                      
5169                 widgetRefresh.run();                                                                     
5170             } else {                                                                                     
5171                 // widgetRefresh will automatically run when the packages are updated.                   
5172             }                                                                                            
5173         }                                                                                                
5174     }                                                                                                    
5175                                                                                                          
5176     private void moveToScreen(int page, boolean animate) {                                               
5177         if (!workspaceInModalState()) {                                                                  
5178             if (animate) {                                                                               
5179                 snapToPage(page);                                                                        
5180             } else {                                                                                     
5181                 setCurrentPage(page);                                                                    
5182             }                                                                                            
5183         }                                                                                                
5184         View child = getChildAt(page);                                                                   
5185         if (child != null) {                                                                             
5186             child.requestFocus();                                                                        
5187         }                                                                                                
5188     }                                                                                                    
5189                                                                                                          
5190     void moveToDefaultScreen(boolean animate) {                                                          
5191         moveToScreen(mDefaultPage, animate);                                                             
5192     }                                                                                                    
5193                                                                                                          
5194     void moveToCustomContentScreen(boolean animate) {                                                    
5195         if (hasCustomContent()) {                                                                        
5196             int ccIndex = getPageIndexForScreenId(CUSTOM_CONTENT_SCREEN_ID);                             
5197             if (animate) {                                                                               
5198                 snapToPage(ccIndex);                                                                     
5199             } else {                                                                                     
5200                 setCurrentPage(ccIndex);                                                                 
5201             }                                                                                            
5202             View child = getChildAt(ccIndex);                                                            
5203             if (child != null) {                                                                         
5204                 child.requestFocus();                                                                    
5205             }                                                                                            
5206          }                                                                                               
5207         exitWidgetResizeMode();                                                                          
5208     }                                                                                                    
5209                                                                                                          
5210     @Override                                                                                            
5211     protected PageIndicator.PageMarkerResources getPageIndicatorMarker(int pageIndex) {                  
5212         long screenId = getScreenIdForPageIndex(pageIndex);                                              
5213         if (screenId == EXTRA_EMPTY_SCREEN_ID) {                                                         
5214             int count = mScreenOrder.size() - numCustomPages();                                          
5215             if (count > 1) {                                                                             
5216                 return new PageIndicator.PageMarkerResources(R.drawable.ic_pageindicator_current,        
5217                         R.drawable.ic_pageindicator_add);                                                
5218             }                                                                                            
5219         }                                                                                                
5220                                                                                                          
5221         return super.getPageIndicatorMarker(pageIndex);                                                  
5222     }                                                                                                    
5223                                                                                                          
5224     @Override                                                                                            
5225     public void syncPages() {                                                                            
5226     }                                                                                                    
5227                                                                                                          
5228     @Override                                                                                            
5229     public void syncPageItems(int page, boolean immediate) {                                             
5230     }                                                                                                    
5231                                                                                                          
5232     protected String getPageIndicatorDescription() {                                                     
5233         String settings = getResources().getString(R.string.settings_button_text);                       
5234         return getCurrentPageDescription() + ", " + settings;                                            
5235     }                                                                                                    
5236                                                                                                          
5237     protected String getCurrentPageDescription() {                                                       
5238         int page = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage;                               
5239         int delta = numCustomPages();                                                                    
5240         if (hasCustomContent() && getNextPage() == 0) {                                                  
5241             return mCustomContentDescription;                                                            
5242         }                                                                                                
5243         return String.format(getContext().getString(R.string.workspace_scroll_format),                   
5244                 page + 1 - delta, getChildCount() - delta);                                              
5245     }                                                                                                    
5246                                                                                                          
5247     public void getLocationInDragLayer(int[] loc) {                                                      
5248         mLauncher.getDragLayer().getLocationInDragLayer(this, loc);                                      
5249     }                                                                                                    
5250                                                                                                          
5251     /**                                                                                                  
5252      * Used as a workaround to ensure that the AppWidgetService receives the                             
5253      * PACKAGE_ADDED broadcast before updating widgets.                                                  
5254      */                                                                                                  
5255     private class DeferredWidgetRefresh implements Runnable {                                            
5256         private final ArrayList<LauncherAppWidgetInfo> mInfos;                                           
5257         private final LauncherAppWidgetHost mHost;                                                       
5258         private final Handler mHandler;                                                                  
5259                                                                                                          
5260         private boolean mRefreshPending;                                                                 
5261                                                                                                          
5262         public DeferredWidgetRefresh(ArrayList<LauncherAppWidgetInfo> infos,                             
5263                 LauncherAppWidgetHost host) {                                                            
5264             mInfos = infos;                                                                              
5265             mHost = host;                                                                                
5266             mHandler = new Handler();                                                                    
5267             mRefreshPending = true;                                                                      
5268                                                                                                          
5269             mHost.addProviderChangeListener(this);                                                       
5270             // Force refresh after 10 seconds, if we don't get the provider changed event.               
5271             // This could happen when the provider is no longer available in the app.                    
5272             mHandler.postDelayed(this, 10000);                                                           
5273         }                                                                                                
5274                                                                                                          
5275         @Override                                                                                        
5276         public void run() {                                                                              
5277             mHost.removeProviderChangeListener(this);                                                    
5278             mHandler.removeCallbacks(this);                                                              
5279                                                                                                          
5280             if (!mRefreshPending) {                                                                      
5281                 return;                                                                                  
5282             }                                                                                            
5283                                                                                                          
5284             mRefreshPending = false;                                                                     
5285                                                                                                          
5286             for (LauncherAppWidgetInfo info : mInfos) {                                                  
5287                 if (info.hostView instanceof PendingAppWidgetHostView) {                                 
5288                     PendingAppWidgetHostView view = (PendingAppWidgetHostView) info.hostView;            
5289                     mLauncher.removeAppWidget(info);                                                     
5290                                                                                                          
5291                     CellLayout cl = (CellLayout) view.getParent().getParent();                           
5292                     // Remove the current widget                                                         
5293                     cl.removeView(view);                                                                 
5294                     mLauncher.bindAppWidget(info);                                                       
5295                 }                                                                                        
5296             }                                                                                            
5297         }                                                                                                
5298     }                                                                                                    
5299 }                                                                                                        
   1 /*                                                                                                       
   2  * Copyright (C) 2008 The Android Open Source Project                                                    
   3  *                                                                                                       
   4  * Licensed under the Apache License, Version 2.0 (the "License");                                       
   5  * you may not use this file except in compliance with the License.                                      
   6  * You may obtain a copy of the License at                                                               
   7  *                                                                                                       
   8  *      http://www.apache.org/licenses/LICENSE-2.0                                                       
   9  *                                                                                                       
  10  * Unless required by applicable law or agreed to in writing, software                                   
  11  * distributed under the License is distributed on an "AS IS" BASIS,                                     
  12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.                              
  13  * See the License for the specific language governing permissions and                                   
  14  * limitations under the License.                                                                        
  15  */                                                                                                      
  16                                                                                                          
  17 package com.android.launcher3;                                                                           
  18                                                                                                          
  19 import android.animation.Animator;                                                                       
  20 import android.animation.Animator.AnimatorListener;                                                      
  21 import android.animation.AnimatorListenerAdapter;                                                        
  22 import android.animation.AnimatorSet;                                                                    
  23 import android.animation.LayoutTransition;                                                               
  24 import android.animation.ObjectAnimator;                                                                 
  25 import android.animation.PropertyValuesHolder;                                                           
  26 import android.animation.TimeInterpolator;                                                               
  27 import android.animation.ValueAnimator;                                                                  
  28 import android.animation.ValueAnimator.AnimatorUpdateListener;                                           
  29 import android.app.WallpaperManager;                                                                     
  30 import android.appwidget.AppWidgetHostView;                                                              
  31 import android.appwidget.AppWidgetProviderInfo;                                                          
  32 import android.content.ComponentName;                                                                    
  33 import android.content.Context;                                                                          
  34 import android.content.Intent;                                                                           
  35 import android.content.SharedPreferences;                                                                
  36 import android.content.pm.PackageManager;                                                                
  37 import android.content.pm.ResolveInfo;                                                                   
  38 import android.content.res.Resources;                                                                    
  39 import android.content.res.TypedArray;                                                                   
  40 import android.graphics.Bitmap;                                                                          
  41 import android.graphics.Canvas;                                                                          
  42 import android.graphics.Matrix;                                                                          
  43 import android.graphics.Paint;                                                                           
  44 import android.graphics.Point;                                                                           
  45 import android.graphics.PointF;                                                                          
  46 import android.graphics.Rect;                                                                            
  47 import android.graphics.Region.Op;                                                                       
  48 import android.graphics.drawable.Drawable;                                                               
  49 import android.net.Uri;                                                                                  
  50 import android.os.AsyncTask;                                                                             
  51 import android.os.Handler;                                                                               
  52 import android.os.IBinder;                                                                               
  53 import android.os.Parcelable;                                                                            
  54 import android.support.v4.view.ViewCompat;                                                               
  55 import android.util.AttributeSet;                                                                        
  56 import android.util.Log;                                                                                 
  57 import android.util.SparseArray;                                                                         
  58 import android.view.Choreographer;                                                                       
  59 import android.view.Display;                                                                             
  60 import android.view.MotionEvent;                                                                         
  61 import android.view.View;                                                                                
  62 import android.view.ViewGroup;                                                                           
  63 import android.view.accessibility.AccessibilityManager;                                                  
  64 import android.view.animation.DecelerateInterpolator;                                                    
  65 import android.view.animation.Interpolator;                                                              
  66 import android.widget.TextView;                                                                          
  67                                                                                                          
  68 import com.android.launcher3.FolderIcon.FolderRingAnimator;                                              
  69 import com.android.launcher3.Launcher.CustomContentCallbacks;                                            
  70 import com.android.launcher3.LauncherSettings.Favorites;                                                 
  71 import com.android.launcher3.compat.PackageInstallerCompat;                                              
  72 import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;                           
  73 import com.android.launcher3.compat.UserHandleCompat;                                                    
  74                                                                                                          
  75 import java.util.ArrayList;                                                                              
  76 import java.util.HashMap;                                                                                
  77 import java.util.HashSet;                                                                                
  78 import java.util.Iterator;                                                                               
  79 import java.util.Map;                                                                                    
  80 import java.util.Set;                                                                                    
  81 import java.util.concurrent.atomic.AtomicInteger;                                                        
  82                                                                                                          
  83 /**                                                                                                      
  84  * The workspace is a wide area with a wallpaper and a finite number of pages.                           
  85  * Each page contains a number of icons, folders or widgets the user can                                 
  86  * interact with. A workspace is meant to be used with a fixed width only.                               
  87  */                                                                                                      
  88 public class Workspace extends SmoothPagedView                                                           
  89         implements DropTarget, DragSource, DragScroller, View.OnTouchListener,                           
  90         DragController.DragListener, LauncherTransitionable, ViewGroup.OnHierarchyChangeListener,        
  91         Insettable {                                                                                     
  92     private static final String TAG = "Launcher.Workspace";                                              
  93                                                                                                          
  94     // Y rotation to apply to the workspace screens                                                      
  95     private static final float WORKSPACE_OVERSCROLL_ROTATION = 24f;                                      
  96                                                                                                          
  97     private static final int CHILDREN_OUTLINE_FADE_OUT_DELAY = 0;                                        
  98     private static final int CHILDREN_OUTLINE_FADE_OUT_DURATION = 375;                                   
  99     private static final int CHILDREN_OUTLINE_FADE_IN_DURATION = 100;                                    
 100                                                                                                          
 101     protected static final int SNAP_OFF_EMPTY_SCREEN_DURATION = 400;                                     
 102     protected static final int FADE_EMPTY_SCREEN_DURATION = 150;                                         
 103                                                                                                          
 104     private static final int BACKGROUND_FADE_OUT_DURATION = 350;                                         
 105     private static final int ADJACENT_SCREEN_DROP_DURATION = 300;                                        
 106     private static final int FLING_THRESHOLD_VELOCITY = 500;                                             
 107                                                                                                          
 108     private static final float ALPHA_CUTOFF_THRESHOLD = 0.01f;                                           
 109                                                                                                          
 110     static final boolean MAP_NO_RECURSE = false;                                                         
 111     static final boolean MAP_RECURSE = true;                                                             
 112                                                                                                          
 113     // These animators are used to fade the children's outlines                                          
 114     private ObjectAnimator mChildrenOutlineFadeInAnimation;                                              
 115     private ObjectAnimator mChildrenOutlineFadeOutAnimation;                                             
 116     private float mChildrenOutlineAlpha = 0;                                                             
 117                                                                                                          
 118     // These properties refer to the background protection gradient used for AllApps and Customize       
 119     private ValueAnimator mBackgroundFadeInAnimation;                                                    
 120     private ValueAnimator mBackgroundFadeOutAnimation;                                                   
 121                                                                                                          
 122     private static final long CUSTOM_CONTENT_GESTURE_DELAY = 200;                                        
 123     private long mTouchDownTime = -1;                                                                    
 124     private long mCustomContentShowTime = -1;                                                            
 125                                                                                                          
 126     private LayoutTransition mLayoutTransition;                                                          
 127     private final WallpaperManager mWallpaperManager;                                                    
 128     private IBinder mWindowToken;                                                                        
 129                                                                                                          
 130     private int mOriginalDefaultPage;                                                                    
 131     private int mDefaultPage;                                                                            
 132                                                                                                          
 133     private ShortcutAndWidgetContainer mDragSourceInternal;                                              
 134     private static boolean sAccessibilityEnabled;                                                        
 135                                                                                                          
 136     // The screen id used for the empty screen always present to the right.                              
 137     final static long EXTRA_EMPTY_SCREEN_ID = -201;                                                      
 138     private final static long CUSTOM_CONTENT_SCREEN_ID = -301;                                           
 139                                                                                                          
 140     private HashMap<Long, CellLayout> mWorkspaceScreens = new HashMap<Long, CellLayout>();               
 141     private ArrayList<Long> mScreenOrder = new ArrayList<Long>();                                        
 142                                                                                                          
 143     private Runnable mRemoveEmptyScreenRunnable;                                                         
 144     private boolean mDeferRemoveExtraEmptyScreen = false;                                                
 145                                                                                                          
 146     /**                                                                                                  
 147      * CellInfo for the cell that is currently being dragged                                             
 148      */                                                                                                  
 149     private CellLayout.CellInfo mDragInfo;                                                               
 150                                                                                                          
 151     /**                                                                                                  
 152      * Target drop area calculated during last acceptDrop call.                                          
 153      */                                                                                                  
 154     private int[] mTargetCell = new int[2];                                                              
 155     private int mDragOverX = -1;                                                                         
 156     private int mDragOverY = -1;                                                                         
 157                                                                                                          
 158     static Rect mLandscapeCellLayoutMetrics = null;                                                      
 159     static Rect mPortraitCellLayoutMetrics = null;                                                       
 160                                                                                                          
 161     CustomContentCallbacks mCustomContentCallbacks;                                                      
 162     boolean mCustomContentShowing;                                                                       
 163     private float mLastCustomContentScrollProgress = -1f;                                                
 164     private String mCustomContentDescription = "";                                                       
 165                                                                                                          
 166     /**                                                                                                  
 167      * The CellLayout that is currently being dragged over                                               
 168      */                                                                                                  
 169     private CellLayout mDragTargetLayout = null;                                                         
 170     /**                                                                                                  
 171      * The CellLayout that we will show as glowing                                                       
 172      */                                                                                                  
 173     private CellLayout mDragOverlappingLayout = null;                                                    
 174                                                                                                          
 175     /**                                                                                                  
 176      * The CellLayout which will be dropped to                                                           
 177      */                                                                                                  
 178     private CellLayout mDropToLayout = null;                                                             
 179                                                                                                          
 180     private Launcher mLauncher;                                                                          
 181     private IconCache mIconCache;                                                                        
 182     private DragController mDragController;                                                              
 183                                                                                                          
 184     // These are temporary variables to prevent having to allocate a new object just to                  
 185     // return an (x, y) value from helper functions. Do NOT use them to maintain other state.            
 186     private int[] mTempCell = new int[2];                                                                
 187     private int[] mTempPt = new int[2];                                                                  
 188     private int[] mTempEstimate = new int[2];                                                            
 189     private float[] mDragViewVisualCenter = new float[2];                                                
 190     private float[] mTempCellLayoutCenterCoordinates = new float[2];                                     
 191     private Matrix mTempInverseMatrix = new Matrix();                                                    
 192                                                                                                          
 193     private SpringLoadedDragController mSpringLoadedDragController;                                      
 194     private float mSpringLoadedShrinkFactor;                                                             
 195     private float mOverviewModeShrinkFactor;                                                             
 196                                                                                                          
 197     // State variable that indicates whether the pages are small (ie when you're                         
 198     // in all apps or customize mode)                                                                    
 199                                                                                                          
 200     enum State { NORMAL, NORMAL_HIDDEN, SPRING_LOADED, OVERVIEW, OVERVIEW_HIDDEN};                       
 201     private State mState = State.NORMAL;                                                                 
 202     private boolean mIsSwitchingState = false;                                                           
 203                                                                                                          
 204     boolean mAnimatingViewIntoPlace = false;                                                             
 205     boolean mIsDragOccuring = false;                                                                     
 206     boolean mChildrenLayersEnabled = true;                                                               
 207                                                                                                          
 208     private boolean mStripScreensOnPageStopMoving = false;                                               
 209                                                                                                          
 210     /** Is the user is dragging an item near the edge of a page? */                                      
 211     private boolean mInScrollArea = false;                                                               
 212                                                                                                          
 213     private HolographicOutlineHelper mOutlineHelper;                                                     
 214     private Bitmap mDragOutline = null;                                                                  
 215     private static final Rect sTempRect = new Rect();                                                    
 216     private final int[] mTempXY = new int[2];                                                            
 217     private int[] mTempVisiblePagesRange = new int[2];                                                   
 218     private boolean mOverscrollEffectSet;                                                                
 219     public static final int DRAG_BITMAP_PADDING = 2;                                                     
 220     private boolean mWorkspaceFadeInAdjacentScreens;                                                     
 221                                                                                                          
 222     WallpaperOffsetInterpolator mWallpaperOffset;                                                        
 223     private boolean mWallpaperIsLiveWallpaper;                                                           
 224     private int mNumPagesForWallpaperParallax;                                                           
 225     private float mLastSetWallpaperOffsetSteps = 0;                                                      
 226                                                                                                          
 227     private Runnable mDelayedResizeRunnable;                                                             
 228     private Runnable mDelayedSnapToPageRunnable;                                                         
 229     private Point mDisplaySize = new Point();                                                            
 230     private int mCameraDistance;                                                                         
 231                                                                                                          
 232     // Variables relating to the creation of user folders by hovering shortcuts over shortcuts           
 233     private static final int FOLDER_CREATION_TIMEOUT = 0;                                                
 234     public static final int REORDER_TIMEOUT = 350;                                                       
 235     private final Alarm mFolderCreationAlarm = new Alarm();                                              
 236     private final Alarm mReorderAlarm = new Alarm();                                                     
 237     private FolderRingAnimator mDragFolderRingAnimator = null;                                           
 238     private FolderIcon mDragOverFolderIcon = null;                                                       
 239     private boolean mCreateUserFolderOnDrop = false;                                                     
 240     private boolean mAddToExistingFolderOnDrop = false;                                                  
 241     private DropTarget.DragEnforcer mDragEnforcer;                                                       
 242     private float mMaxDistanceForFolderCreation;                                                         
 243                                                                                                          
 244     private final Canvas mCanvas = new Canvas();                                                         
 245                                                                                                          
 246     // Variables relating to touch disambiguation (scrolling workspace vs. scrolling a widget)           
 247     private float mXDown;                                                                                
 248     private float mYDown;                                                                                
 249     final static float START_DAMPING_TOUCH_SLOP_ANGLE = (float) Math.PI / 6;                             
 250     final static float MAX_SWIPE_ANGLE = (float) Math.PI / 3;                                            
 251     final static float TOUCH_SLOP_DAMPING_FACTOR = 4;                                                    
 252                                                                                                          
 253     // Relating to the animation of items being dropped externally                                       
 254     public static final int ANIMATE_INTO_POSITION_AND_DISAPPEAR = 0;                                     
 255     public static final int ANIMATE_INTO_POSITION_AND_REMAIN = 1;                                        
 256     public static final int ANIMATE_INTO_POSITION_AND_RESIZE = 2;                                        
 257     public static final int COMPLETE_TWO_STAGE_WIDGET_DROP_ANIMATION = 3;                                
 258     public static final int CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION = 4;                                  
 259                                                                                                          
 260     // Related to dragging, folder creation and reordering                                               
 261     private static final int DRAG_MODE_NONE = 0;                                                         
 262     private static final int DRAG_MODE_CREATE_FOLDER = 1;                                                
 263     private static final int DRAG_MODE_ADD_TO_FOLDER = 2;                                                
 264     private static final int DRAG_MODE_REORDER = 3;                                                      
 265     private int mDragMode = DRAG_MODE_NONE;                                                              
 266     private int mLastReorderX = -1;                                                                      
 267     private int mLastReorderY = -1;                                                                      
 268                                                                                                          
 269     private SparseArray<Parcelable> mSavedStates;                                                        
 270     private final ArrayList<Integer> mRestoredPages = new ArrayList<Integer>();                          
 271                                                                                                          
 272     // These variables are used for storing the initial and final values during workspace animations     
 273     private int mSavedScrollX;                                                                           
 274     private float mSavedRotationY;                                                                       
 275     private float mSavedTranslationX;                                                                    
 276                                                                                                          
 277     private float mCurrentScale;                                                                         
 278     private float mNewScale;                                                                             
 279     private float[] mOldBackgroundAlphas;                                                                
 280     private float[] mOldAlphas;                                                                          
 281     private float[] mNewBackgroundAlphas;                                                                
 282     private float[] mNewAlphas;                                                                          
 283     private int mLastChildCount = -1;                                                                    
 284     private float mTransitionProgress;                                                                   
 285                                                                                                          
 286     float mOverScrollEffect = 0f;                                                                        
 287                                                                                                          
 288     private Runnable mDeferredAction;                                                                    
 289     private boolean mDeferDropAfterUninstall;                                                            
 290     private boolean mUninstallSuccessful;                                                                
 291                                                                                                          
 292     private final Runnable mBindPages = new Runnable() {                                                 
 293         @Override                                                                                        
 294         public void run() {                                                                              
 295             mLauncher.getModel().bindRemainingSynchronousPages();                                        
 296         }                                                                                                
 297     };                                                                                                   
 298                                                                                                          
 299     /**                                                                                                  
 300      * Used to inflate the Workspace from XML.                                                           
 301      *                                                                                                   
 302      * @param context The application's context.                                                         
 303      * @param attrs The attributes set containing the Workspace's customization values.                  
 304      */                                                                                                  
 305     public Workspace(Context context, AttributeSet attrs) {                                              
 306         this(context, attrs, 0);                                                                         
 307     }                                                                                                    
 308                                                                                                          
 309     /**                                                                                                  
 310      * Used to inflate the Workspace from XML.                                                           
 311      *                                                                                                   
 312      * @param context The application's context.                                                         
 313      * @param attrs The attributes set containing the Workspace's customization values.                  
 314      * @param defStyle Unused.                                                                           
 315      */                                                                                                  
 316     public Workspace(Context context, AttributeSet attrs, int defStyle) {                                
 317         super(context, attrs, defStyle);                                                                 
 318         mContentIsRefreshable = false;                                                                   
 319                                                                                                          
 320         mOutlineHelper = HolographicOutlineHelper.obtain(context);                                       
 321                                                                                                          
 322         mDragEnforcer = new DropTarget.DragEnforcer(context);                                            
 323         // With workspace, data is available straight from the get-go                                    
 324         setDataIsReady();                                                                                
 325                                                                                                          
 326         mLauncher = (Launcher) context;                                                                  
 327         final Resources res = getResources();                                                            
 328         mWorkspaceFadeInAdjacentScreens = LauncherAppState.getInstance().getDynamicGrid().               
 329                 getDeviceProfile().shouldFadeAdjacentWorkspaceScreens();                                 
 330         mFadeInAdjacentScreens = false;                                                                  
 331         mWallpaperManager = WallpaperManager.getInstance(context);                                       
 332                                                                                                          
 333         LauncherAppState app = LauncherAppState.getInstance();                                           
 334         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                    
 335         TypedArray a = context.obtainStyledAttributes(attrs,                                             
 336                 R.styleable.Workspace, defStyle, 0);                                                     
 337         mSpringLoadedShrinkFactor =                                                                      
 338             res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f;               
 339         mOverviewModeShrinkFactor = grid.getOverviewModeScale();                                         
 340         mCameraDistance = res.getInteger(R.integer.config_cameraDistance);                               
 341         mOriginalDefaultPage = mDefaultPage = a.getInt(R.styleable.Workspace_defaultScreen, 1);          
 342         a.recycle();                                                                                     
 343                                                                                                          
 344         setOnHierarchyChangeListener(this);                                                              
 345         setHapticFeedbackEnabled(false);                                                                 
 346                                                                                                          
 347         initWorkspace();                                                                                 
 348                                                                                                          
 349         // Disable multitouch across the workspace/all apps/customize tray                               
 350         setMotionEventSplittingEnabled(true);                                                            
 351         setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);                              
 352     }                                                                                                    
 353                                                                                                          
 354     @Override                                                                                            
 355     public void setInsets(Rect insets) {                                                                 
 356         mInsets.set(insets);                                                                             
 357                                                                                                          
 358         CellLayout customScreen = getScreenWithId(CUSTOM_CONTENT_SCREEN_ID);                             
 359         if (customScreen != null) {                                                                      
 360             View customContent = customScreen.getShortcutsAndWidgets().getChildAt(0);                    
 361             if (customContent instanceof Insettable) {                                                   
 362                 ((Insettable) customContent).setInsets(mInsets);                                         
 363             }                                                                                            
 364         }                                                                                                
 365     }                                                                                                    
 366                                                                                                          
 367     // estimate the size of a widget with spans hSpan, vSpan. return MAX_VALUE for each                  
 368     // dimension if unsuccessful                                                                         
 369     public int[] estimateItemSize(int hSpan, int vSpan,                                                  
 370             ItemInfo itemInfo, boolean springLoaded) {                                                   
 371         int[] size = new int[2];                                                                         
 372         if (getChildCount() > 0) {                                                                       
 373             // Use the first non-custom page to estimate the child position                              
 374             CellLayout cl = (CellLayout) getChildAt(numCustomPages());                                   
 375             Rect r = estimateItemPosition(cl, itemInfo, 0, 0, hSpan, vSpan);                             
 376             size[0] = r.width();                                                                         
 377             size[1] = r.height();                                                                        
 378             if (springLoaded) {                                                                          
 379                 size[0] *= mSpringLoadedShrinkFactor;                                                    
 380                 size[1] *= mSpringLoadedShrinkFactor;                                                    
 381             }                                                                                            
 382             return size;                                                                                 
 383         } else {                                                                                         
 384             size[0] = Integer.MAX_VALUE;                                                                 
 385             size[1] = Integer.MAX_VALUE;                                                                 
 386             return size;                                                                                 
 387         }                                                                                                
 388     }                                                                                                    
 389                                                                                                          
 390     public Rect estimateItemPosition(CellLayout cl, ItemInfo pendingInfo,                                
 391             int hCell, int vCell, int hSpan, int vSpan) {                                                
 392         Rect r = new Rect();                                                                             
 393         cl.cellToRect(hCell, vCell, hSpan, vSpan, r);                                                    
 394         return r;                                                                                        
 395     }                                                                                                    
 396                                                                                                          
 397     public void onDragStart(final DragSource source, Object info, int dragAction) {                      
 398         mIsDragOccuring = true;                                                                          
 399         updateChildrenLayersEnabled(false);                                                              
 400         mLauncher.lockScreenOrientation();                                                               
 401         mLauncher.onInteractionBegin();                                                                  
 402         setChildrenBackgroundAlphaMultipliers(1f);                                                       
 403         // Prevent any Un/InstallShortcutReceivers from updating the db while we are dragging            
 404         InstallShortcutReceiver.enableInstallQueue();                                                    
 405         UninstallShortcutReceiver.enableUninstallQueue();                                                
 406         post(new Runnable() {                                                                            
 407             @Override                                                                                    
 408             public void run() {                                                                          
 409                 if (mIsDragOccuring) {                                                                   
 410                     mDeferRemoveExtraEmptyScreen = false;                                                
 411                     addExtraEmptyScreenOnDrag();                                                         
 412                 }                                                                                        
 413             }                                                                                            
 414         });                                                                                              
 415     }                                                                                                    
 416                                                                                                          
 417                                                                                                          
 418     public void deferRemoveExtraEmptyScreen() {                                                          
 419         mDeferRemoveExtraEmptyScreen = true;                                                             
 420     }                                                                                                    
 421                                                                                                          
 422     public void onDragEnd() {                                                                            
 423         if (!mDeferRemoveExtraEmptyScreen) {                                                             
 424             removeExtraEmptyScreen(true, mDragSourceInternal != null);                                   
 425         }                                                                                                
 426                                                                                                          
 427         mIsDragOccuring = false;                                                                         
 428         updateChildrenLayersEnabled(false);                                                              
 429         mLauncher.unlockScreenOrientation(false);                                                        
 430                                                                                                          
 431         // Re-enable any Un/InstallShortcutReceiver and now process any queued items                     
 432         InstallShortcutReceiver.disableAndFlushInstallQueue(getContext());                               
 433         UninstallShortcutReceiver.disableAndFlushUninstallQueue(getContext());                           
 434                                                                                                          
 435         mDragSourceInternal = null;                                                                      
 436         mLauncher.onInteractionEnd();                                                                    
 437     }                                                                                                    
 438                                                                                                          
 439     /**                                                                                                  
 440      * Initializes various states for this workspace.                                                    
 441      */                                                                                                  
 442     protected void initWorkspace() {                                                                     
 443         mCurrentPage = mDefaultPage;                                                                     
 444         Launcher.setScreen(mCurrentPage);                                                                
 445         LauncherAppState app = LauncherAppState.getInstance();                                           
 446         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                    
 447         mIconCache = app.getIconCache();                                                                 
 448         setWillNotDraw(false);                                                                           
 449         setClipChildren(false);                                                                          
 450         setClipToPadding(false);                                                                         
 451         setChildrenDrawnWithCacheEnabled(true);                                                          
 452                                                                                                          
 453         setMinScale(mOverviewModeShrinkFactor);                                                          
 454         setupLayoutTransition();                                                                         
 455                                                                                                          
 456         mWallpaperOffset = new WallpaperOffsetInterpolator();                                            
 457         Display display = mLauncher.getWindowManager().getDefaultDisplay();                              
 458         display.getSize(mDisplaySize);                                                                   
 459                                                                                                          
 460         mMaxDistanceForFolderCreation = (0.55f * grid.iconSizePx);                                       
 461         mFlingThresholdVelocity = (int) (FLING_THRESHOLD_VELOCITY * mDensity);                           
 462                                                                                                          
 463         // Set the wallpaper dimensions when Launcher starts up                                          
 464         setWallpaperDimension();                                                                         
 465     }                                                                                                    
 466                                                                                                          
 467     private void setupLayoutTransition() {                                                               
 468         // We want to show layout transitions when pages are deleted, to close the gap.                  
 469         mLayoutTransition = new LayoutTransition();                                                      
 470         mLayoutTransition.enableTransitionType(LayoutTransition.DISAPPEARING);                           
 471         mLayoutTransition.enableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);                    
 472         mLayoutTransition.disableTransitionType(LayoutTransition.APPEARING);                             
 473         mLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_APPEARING);                      
 474         setLayoutTransition(mLayoutTransition);                                                          
 475     }                                                                                                    
 476                                                                                                          
 477     void enableLayoutTransitions() {                                                                     
 478         setLayoutTransition(mLayoutTransition);                                                          
 479     }                                                                                                    
 480     void disableLayoutTransitions() {                                                                    
 481         setLayoutTransition(null);                                                                       
 482     }                                                                                                    
 483                                                                                                          
 484     @Override                                                                                            
 485     protected int getScrollMode() {                                                                      
 486         return SmoothPagedView.X_LARGE_MODE;                                                             
 487     }                                                                                                    
 488                                                                                                          
 489     @Override                                                                                            
 490     public void onChildViewAdded(View parent, View child) {                                              
 491         if (!(child instanceof CellLayout)) {                                                            
 492             throw new IllegalArgumentException("A Workspace can only have CellLayout children.");        
 493         }                                                                                                
 494         CellLayout cl = ((CellLayout) child);                                                            
 495         cl.setOnInterceptTouchListener(this);                                                            
 496         cl.setClickable(true);                                                                           
 497         cl.setImportantForAccessibility(ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO);                      
 498         super.onChildViewAdded(parent, child);                                                           
 499     }                                                                                                    
 500                                                                                                          
 501     protected boolean shouldDrawChild(View child) {                                                      
 502         final CellLayout cl = (CellLayout) child;                                                        
 503         return super.shouldDrawChild(child) &&                                                           
 504             (mIsSwitchingState ||                                                                        
 505              cl.getShortcutsAndWidgets().getAlpha() > 0 ||                                               
 506              cl.getBackgroundAlpha() > 0);                                                               
 507     }                                                                                                    
 508                                                                                                          
 509     /**                                                                                                  
 510      * @return The open folder on the current screen, or null if there is none                           
 511      */                                                                                                  
 512     Folder getOpenFolder() {                                                                             
 513         DragLayer dragLayer = mLauncher.getDragLayer();                                                  
 514         int count = dragLayer.getChildCount();                                                           
 515         for (int i = 0; i < count; i++) {                                                                
 516             View child = dragLayer.getChildAt(i);                                                        
 517             if (child instanceof Folder) {                                                               
 518                 Folder folder = (Folder) child;                                                          
 519                 if (folder.getInfo().opened)                                                             
 520                     return folder;                                                                       
 521             }                                                                                            
 522         }                                                                                                
 523         return null;                                                                                     
 524     }                                                                                                    
 525                                                                                                          
 526     boolean isTouchActive() {                                                                            
 527         return mTouchState != TOUCH_STATE_REST;                                                          
 528     }                                                                                                    
 529                                                                                                          
 530     public void removeAllWorkspaceScreens() {                                                            
 531         // Disable all layout transitions before removing all pages to ensure that we don't get the      
 532         // transition animations competing with us changing the scroll when we add pages or the          
 533         // custom content screen                                                                         
 534         disableLayoutTransitions();                                                                      
 535                                                                                                          
 536         // Since we increment the current page when we call addCustomContentPage via bindScreens         
 537         // (and other places), we need to adjust the current page back when we clear the pages           
 538         if (hasCustomContent()) {                                                                        
 539             removeCustomContentPage();                                                                   
 540         }                                                                                                
 541                                                                                                          
 542         // Remove the pages and clear the screen models                                                  
 543         removeAllViews();                                                                                
 544         mScreenOrder.clear();                                                                            
 545         mWorkspaceScreens.clear();                                                                       
 546                                                                                                          
 547         // Re-enable the layout transitions                                                              
 548         enableLayoutTransitions();                                                                       
 549     }                                                                                                    
 550                                                                                                          
 551     public long insertNewWorkspaceScreenBeforeEmptyScreen(long screenId) {                               
 552         // Find the index to insert this view into.  If the empty screen exists, then                    
 553         // insert it before that.                                                                        
 554         int insertIndex = mScreenOrder.indexOf(EXTRA_EMPTY_SCREEN_ID);                                   
 555         if (insertIndex < 0) {                                                                           
 556             insertIndex = mScreenOrder.size();                                                           
 557         }                                                                                                
 558         return insertNewWorkspaceScreen(screenId, insertIndex);                                          
 559     }                                                                                                    
 560                                                                                                          
 561     public long insertNewWorkspaceScreen(long screenId) {                                                
 562         return insertNewWorkspaceScreen(screenId, getChildCount());                                      
 563     }                                                                                                    
 564                                                                                                          
 565     public long insertNewWorkspaceScreen(long screenId, int insertIndex) {                               
 566         // Log to disk                                                                                   
 567         Launcher.addDumpLog(TAG, "11683562 - insertNewWorkspaceScreen(): " + screenId +                  
 568                 " at index: " + insertIndex, true);                                                      
 569                                                                                                          
 570         if (mWorkspaceScreens.containsKey(screenId)) {                                                   
 571             throw new RuntimeException("Screen id " + screenId + " already exists!");                    
 572         }                                                                                                
 573                                                                                                          
 574         CellLayout newScreen = (CellLayout)                                                              
 575                 mLauncher.getLayoutInflater().inflate(R.layout.workspace_screen, null);                  
 576                                                                                                          
 577         newScreen.setOnLongClickListener(mLongClickListener);                                            
 578         newScreen.setOnClickListener(mLauncher);                                                         
 579         newScreen.setSoundEffectsEnabled(false);                                                         
 580         mWorkspaceScreens.put(screenId, newScreen);                                                      
 581         mScreenOrder.add(insertIndex, screenId);                                                         
 582         addView(newScreen, insertIndex);                                                                 
 583         return screenId;                                                                                 
 584     }                                                                                                    
 585                                                                                                          
 586     public void createCustomContentContainer() {                                                         
 587         CellLayout customScreen = (CellLayout)                                                           
 588                 mLauncher.getLayoutInflater().inflate(R.layout.workspace_screen, null);                  
 589         customScreen.disableBackground();                                                                
 590         customScreen.disableDragTarget();                                                                
 591                                                                                                          
 592         mWorkspaceScreens.put(CUSTOM_CONTENT_SCREEN_ID, customScreen);                                   
 593         mScreenOrder.add(0, CUSTOM_CONTENT_SCREEN_ID);                                                   
 594                                                                                                          
 595         // We want no padding on the custom content                                                      
 596         customScreen.setPadding(0, 0, 0, 0);                                                             
 597                                                                                                          
 598         addFullScreenPage(customScreen);                                                                 
 599                                                                                                          
 600         // Ensure that the current page and default page are maintained.                                 
 601         mDefaultPage = mOriginalDefaultPage + 1;                                                         
 602                                                                                                          
 603         // Update the custom content hint                                                                
 604         if (mRestorePage != INVALID_RESTORE_PAGE) {                                                      
 605             mRestorePage = mRestorePage + 1;                                                             
 606         } else {                                                                                         
 607             setCurrentPage(getCurrentPage() + 1);                                                        
 608         }                                                                                                
 609     }                                                                                                    
 610                                                                                                          
 611     public void removeCustomContentPage() {                                                              
 612         CellLayout customScreen = getScreenWithId(CUSTOM_CONTENT_SCREEN_ID);                             
 613         if (customScreen == null) {                                                                      
 614             throw new RuntimeException("Expected custom content screen to exist");                       
 615         }                                                                                                
 616                                                                                                          
 617         mWorkspaceScreens.remove(CUSTOM_CONTENT_SCREEN_ID);                                              
 618         mScreenOrder.remove(CUSTOM_CONTENT_SCREEN_ID);                                                   
 619         removeView(customScreen);                                                                        
 620                                                                                                          
 621         if (mCustomContentCallbacks != null) {                                                           
 622             mCustomContentCallbacks.onScrollProgressChanged(0);                                          
 623             mCustomContentCallbacks.onHide();                                                            
 624         }                                                                                                
 625                                                                                                          
 626         mCustomContentCallbacks = null;                                                                  
 627                                                                                                          
 628         // Ensure that the current page and default page are maintained.                                 
 629         mDefaultPage = mOriginalDefaultPage - 1;                                                         
 630                                                                                                          
 631         // Update the custom content hint                                                                
 632         if (mRestorePage != INVALID_RESTORE_PAGE) {                                                      
 633             mRestorePage = mRestorePage - 1;                                                             
 634         } else {                                                                                         
 635             setCurrentPage(getCurrentPage() - 1);                                                        
 636         }                                                                                                
 637     }                                                                                                    
 638                                                                                                          
 639     public void addToCustomContentPage(View customContent, CustomContentCallbacks callbacks,             
 640             String description) {                                                                        
 641         if (getPageIndexForScreenId(CUSTOM_CONTENT_SCREEN_ID) < 0) {                                     
 642             throw new RuntimeException("Expected custom content screen to exist");                       
 643         }                                                                                                
 644                                                                                                          
 645         // Add the custom content to the full screen custom page                                         
 646         CellLayout customScreen = getScreenWithId(CUSTOM_CONTENT_SCREEN_ID);                             
 647         int spanX = customScreen.getCountX();                                                            
 648         int spanY = customScreen.getCountY();                                                            
 649         CellLayout.LayoutParams lp = new CellLayout.LayoutParams(0, 0, spanX, spanY);                    
 650         lp.canReorder  = false;                                                                          
 651         lp.isFullscreen = true;                                                                          
 652         if (customContent instanceof Insettable) {                                                       
 653             ((Insettable)customContent).setInsets(mInsets);                                              
 654         }                                                                                                
 655                                                                                                          
 656         // Verify that the child is removed from any existing parent.                                    
 657         if (customContent.getParent() instanceof ViewGroup) {                                            
 658             ViewGroup parent = (ViewGroup) customContent.getParent();                                    
 659             parent.removeView(customContent);                                                            
 660         }                                                                                                
 661         customScreen.removeAllViews();                                                                   
 662         customScreen.addViewToCellLayout(customContent, 0, 0, lp, true);                                 
 663         mCustomContentDescription = description;                                                         
 664                                                                                                          
 665         mCustomContentCallbacks = callbacks;                                                             
 666     }                                                                                                    
 667                                                                                                          
 668     public void addExtraEmptyScreenOnDrag() {                                                            
 669         // Log to disk                                                                                   
 670         Launcher.addDumpLog(TAG, "11683562 - addExtraEmptyScreenOnDrag()", true);                        
 671                                                                                                          
 672         boolean lastChildOnScreen = false;                                                               
 673         boolean childOnFinalScreen = false;                                                              
 674                                                                                                          
 675         // Cancel any pending removal of empty screen                                                    
 676         mRemoveEmptyScreenRunnable = null;                                                               
 677                                                                                                          
 678         if (mDragSourceInternal != null) {                                                               
 679             if (mDragSourceInternal.getChildCount() == 1) {                                              
 680                 lastChildOnScreen = true;                                                                
 681             }                                                                                            
 682             CellLayout cl = (CellLayout) mDragSourceInternal.getParent();                                
 683             if (indexOfChild(cl) == getChildCount() - 1) {                                               
 684                 childOnFinalScreen = true;                                                               
 685             }                                                                                            
 686         }                                                                                                
 687                                                                                                          
 688         // If this is the last item on the final screen                                                  
 689         if (lastChildOnScreen && childOnFinalScreen) {                                                   
 690             return;                                                                                      
 691         }                                                                                                
 692         if (!mWorkspaceScreens.containsKey(EXTRA_EMPTY_SCREEN_ID)) {                                     
 693             insertNewWorkspaceScreen(EXTRA_EMPTY_SCREEN_ID);                                             
 694         }                                                                                                
 695     }                                                                                                    
 696                                                                                                          
 697     public boolean addExtraEmptyScreen() {                                                               
 698         // Log to disk                                                                                   
 699         Launcher.addDumpLog(TAG, "11683562 - addExtraEmptyScreen()", true);                              
 700                                                                                                          
 701         if (!mWorkspaceScreens.containsKey(EXTRA_EMPTY_SCREEN_ID)) {                                     
 702             insertNewWorkspaceScreen(EXTRA_EMPTY_SCREEN_ID);                                             
 703             return true;                                                                                 
 704         }                                                                                                
 705         return false;                                                                                    
 706     }                                                                                                    
 707                                                                                                          
 708     private void convertFinalScreenToEmptyScreenIfNecessary() {                                          
 709         // Log to disk                                                                                   
 710         Launcher.addDumpLog(TAG, "11683562 - convertFinalScreenToEmptyScreenIfNecessary()", true);       
 711                                                                                                          
 712         if (mLauncher.isWorkspaceLoading()) {                                                            
 713             // Invalid and dangerous operation if workspace is loading                                   
 714             Launcher.addDumpLog(TAG, "    - workspace loading, skip", true);                             
 715             return;                                                                                      
 716         }                                                                                                
 717                                                                                                          
 718         if (hasExtraEmptyScreen() || mScreenOrder.size() == 0) return;                                   
 719         long finalScreenId = mScreenOrder.get(mScreenOrder.size() - 1);                                  
 720                                                                                                          
 721         if (finalScreenId == CUSTOM_CONTENT_SCREEN_ID) return;                                           
 722         CellLayout finalScreen = mWorkspaceScreens.get(finalScreenId);                                   
 723                                                                                                          
 724         // If the final screen is empty, convert it to the extra empty screen                            
 725         if (finalScreen.getShortcutsAndWidgets().getChildCount() == 0 &&                                 
 726                 !finalScreen.isDropPending()) {                                                          
 727             mWorkspaceScreens.remove(finalScreenId);                                                     
 728             mScreenOrder.remove(finalScreenId);                                                          
 729                                                                                                          
 730             // if this is the last non-custom content screen, convert it to the empty screen             
 731             mWorkspaceScreens.put(EXTRA_EMPTY_SCREEN_ID, finalScreen);                                   
 732             mScreenOrder.add(EXTRA_EMPTY_SCREEN_ID);                                                     
 733                                                                                                          
 734             // Update the model if we have changed any screens                                           
 735             mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder);                    
 736             Launcher.addDumpLog(TAG, "11683562 -   extra empty screen: " + finalScreenId, true);         
 737         }                                                                                                
 738     }                                                                                                    
 739                                                                                                          
 740     public void removeExtraEmptyScreen(final boolean animate, boolean stripEmptyScreens) {               
 741         removeExtraEmptyScreenDelayed(animate, null, 0, stripEmptyScreens);                              
 742     }                                                                                                    
 743                                                                                                          
 744     public void removeExtraEmptyScreenDelayed(final boolean animate, final Runnable onComplete,          
 745             final int delay, final boolean stripEmptyScreens) {                                          
 746         // Log to disk                                                                                   
 747         Launcher.addDumpLog(TAG, "11683562 - removeExtraEmptyScreen()", true);                           
 748         if (mLauncher.isWorkspaceLoading()) {                                                            
 749             // Don't strip empty screens if the workspace is still loading                               
 750             Launcher.addDumpLog(TAG, "    - workspace loading, skip", true);                             
 751             return;                                                                                      
 752         }                                                                                                
 753                                                                                                          
 754         if (delay > 0) {                                                                                 
 755             postDelayed(new Runnable() {                                                                 
 756                 @Override                                                                                
 757                 public void run() {                                                                      
 758                     removeExtraEmptyScreenDelayed(animate, onComplete, 0, stripEmptyScreens);            
 759                 }                                                                                        
 760             }, delay);                                                                                   
 761             return;                                                                                      
 762         }                                                                                                
 763                                                                                                          
 764         convertFinalScreenToEmptyScreenIfNecessary();                                                    
 765         if (hasExtraEmptyScreen()) {                                                                     
 766             int emptyIndex = mScreenOrder.indexOf(EXTRA_EMPTY_SCREEN_ID);                                
 767             if (getNextPage() == emptyIndex) {                                                           
 768                 snapToPage(getNextPage() - 1, SNAP_OFF_EMPTY_SCREEN_DURATION);                           
 769                 fadeAndRemoveEmptyScreen(SNAP_OFF_EMPTY_SCREEN_DURATION, FADE_EMPTY_SCREEN_DURATION,     
 770                         onComplete, stripEmptyScreens);                                                  
 771             } else {                                                                                     
 772                 fadeAndRemoveEmptyScreen(0, FADE_EMPTY_SCREEN_DURATION,                                  
 773                         onComplete, stripEmptyScreens);                                                  
 774             }                                                                                            
 775             return;                                                                                      
 776         } else if (stripEmptyScreens) {                                                                  
 777             // If we're not going to strip the empty screens after removing                              
 778             // the extra empty screen, do it right away.                                                 
 779             stripEmptyScreens();                                                                         
 780         }                                                                                                
 781                                                                                                          
 782         if (onComplete != null) {                                                                        
 783             onComplete.run();                                                                            
 784         }                                                                                                
 785     }                                                                                                    
 786                                                                                                          
 787     private void fadeAndRemoveEmptyScreen(int delay, int duration, final Runnable onComplete,            
 788             final boolean stripEmptyScreens) {                                                           
 789         // Log to disk                                                                                   
 790         // XXX: Do we need to update LM workspace screens below?                                         
 791         Launcher.addDumpLog(TAG, "11683562 - fadeAndRemoveEmptyScreen()", true);                         
 792         PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 0f);                          
 793         PropertyValuesHolder bgAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha", 0f);              
 794                                                                                                          
 795         final CellLayout cl = mWorkspaceScreens.get(EXTRA_EMPTY_SCREEN_ID);                              
 796                                                                                                          
 797         mRemoveEmptyScreenRunnable = new Runnable() {                                                    
 798             @Override                                                                                    
 799             public void run() {                                                                          
 800                 if (hasExtraEmptyScreen()) {                                                             
 801                     mWorkspaceScreens.remove(EXTRA_EMPTY_SCREEN_ID);                                     
 802                     mScreenOrder.remove(EXTRA_EMPTY_SCREEN_ID);                                          
 803                     removeView(cl);                                                                      
 804                     if (stripEmptyScreens) {                                                             
 805                         stripEmptyScreens();                                                             
 806                     }                                                                                    
 807                 }                                                                                        
 808             }                                                                                            
 809         };                                                                                               
 810                                                                                                          
 811         ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(cl, alpha, bgAlpha);                   
 812         oa.setDuration(duration);                                                                        
 813         oa.setStartDelay(delay);                                                                         
 814         oa.addListener(new AnimatorListenerAdapter() {                                                   
 815             @Override                                                                                    
 816             public void onAnimationEnd(Animator animation) {                                             
 817                 if (mRemoveEmptyScreenRunnable != null) {                                                
 818                     mRemoveEmptyScreenRunnable.run();                                                    
 819                 }                                                                                        
 820                 if (onComplete != null) {                                                                
 821                     onComplete.run();                                                                    
 822                 }                                                                                        
 823             }                                                                                            
 824         });                                                                                              
 825         oa.start();                                                                                      
 826     }                                                                                                    
 827                                                                                                          
 828     public boolean hasExtraEmptyScreen() {                                                               
 829         int nScreens = getChildCount();                                                                  
 830         nScreens = nScreens - numCustomPages();                                                          
 831         return mWorkspaceScreens.containsKey(EXTRA_EMPTY_SCREEN_ID) && nScreens > 1;                     
 832     }                                                                                                    
 833                                                                                                          
 834     public long commitExtraEmptyScreen() {                                                               
 835         // Log to disk                                                                                   
 836         Launcher.addDumpLog(TAG, "11683562 - commitExtraEmptyScreen()", true);                           
 837         if (mLauncher.isWorkspaceLoading()) {                                                            
 838             // Invalid and dangerous operation if workspace is loading                                   
 839             Launcher.addDumpLog(TAG, "    - workspace loading, skip", true);                             
 840             return -1;                                                                                   
 841         }                                                                                                
 842                                                                                                          
 843         int index = getPageIndexForScreenId(EXTRA_EMPTY_SCREEN_ID);                                      
 844         CellLayout cl = mWorkspaceScreens.get(EXTRA_EMPTY_SCREEN_ID);                                    
 845         mWorkspaceScreens.remove(EXTRA_EMPTY_SCREEN_ID);                                                 
 846         mScreenOrder.remove(EXTRA_EMPTY_SCREEN_ID);                                                      
 847                                                                                                          
 848         long newId = LauncherAppState.getLauncherProvider().generateNewScreenId();                       
 849         mWorkspaceScreens.put(newId, cl);                                                                
 850         mScreenOrder.add(newId);                                                                         
 851                                                                                                          
 852         // Update the page indicator marker                                                              
 853         if (getPageIndicator() != null) {                                                                
 854             getPageIndicator().updateMarker(index, getPageIndicatorMarker(index));                       
 855         }                                                                                                
 856                                                                                                          
 857         // Update the model for the new screen                                                           
 858         mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder);                        
 859                                                                                                          
 860         return newId;                                                                                    
 861     }                                                                                                    
 862                                                                                                          
 863     public CellLayout getScreenWithId(long screenId) {                                                   
 864         CellLayout layout = mWorkspaceScreens.get(screenId);                                             
 865         return layout;                                                                                   
 866     }                                                                                                    
 867                                                                                                          
 868     public long getIdForScreen(CellLayout layout) {                                                      
 869         Iterator<Long> iter = mWorkspaceScreens.keySet().iterator();                                     
 870         while (iter.hasNext()) {                                                                         
 871             long id = iter.next();                                                                       
 872             if (mWorkspaceScreens.get(id) == layout) {                                                   
 873                 return id;                                                                               
 874             }                                                                                            
 875         }                                                                                                
 876         return -1;                                                                                       
 877     }                                                                                                    
 878                                                                                                          
 879     public int getPageIndexForScreenId(long screenId) {                                                  
 880         return indexOfChild(mWorkspaceScreens.get(screenId));                                            
 881     }                                                                                                    
 882                                                                                                          
 883     public long getScreenIdForPageIndex(int index) {                                                     
 884         if (0 <= index && index < mScreenOrder.size()) {                                                 
 885             return mScreenOrder.get(index);                                                              
 886         }                                                                                                
 887         return -1;                                                                                       
 888     }                                                                                                    
 889                                                                                                          
 890     ArrayList<Long> getScreenOrder() {                                                                   
 891         return mScreenOrder;                                                                             
 892     }                                                                                                    
 893                                                                                                          
 894     public void stripEmptyScreens() {                                                                    
 895         // Log to disk                                                                                   
 896         Launcher.addDumpLog(TAG, "11683562 - stripEmptyScreens()", true);                                
 897                                                                                                          
 898         if (mLauncher.isWorkspaceLoading()) {                                                            
 899             // Don't strip empty screens if the workspace is still loading.                              
 900             // This is dangerous and can result in data loss.                                            
 901             Launcher.addDumpLog(TAG, "    - workspace loading, skip", true);                             
 902             return;                                                                                      
 903         }                                                                                                
 904                                                                                                          
 905         if (isPageMoving()) {                                                                            
 906             mStripScreensOnPageStopMoving = true;                                                        
 907             return;                                                                                      
 908         }                                                                                                
 909                                                                                                          
 910         int currentPage = getNextPage();                                                                 
 911         ArrayList<Long> removeScreens = new ArrayList<Long>();                                           
 912         for (Long id: mWorkspaceScreens.keySet()) {                                                      
 913             CellLayout cl = mWorkspaceScreens.get(id);                                                   
 914             if (id >= 0 && cl.getShortcutsAndWidgets().getChildCount() == 0) {                           
 915                 removeScreens.add(id);                                                                   
 916             }                                                                                            
 917         }                                                                                                
 918                                                                                                          
 919         // We enforce at least one page to add new items to. In the case that we remove the last         
 920         // such screen, we convert the last screen to the empty screen                                   
 921         int minScreens = 1 + numCustomPages();                                                           
 922                                                                                                          
 923         int pageShift = 0;                                                                               
 924         for (Long id: removeScreens) {                                                                   
 925             Launcher.addDumpLog(TAG, "11683562 -   removing id: " + id, true);                           
 926             CellLayout cl = mWorkspaceScreens.get(id);                                                   
 927             mWorkspaceScreens.remove(id);                                                                
 928             mScreenOrder.remove(id);                                                                     
 929                                                                                                          
 930             if (getChildCount() > minScreens) {                                                          
 931                 if (indexOfChild(cl) < currentPage) {                                                    
 932                     pageShift++;                                                                         
 933                 }                                                                                        
 934                 removeView(cl);                                                                          
 935             } else {                                                                                     
 936                 // if this is the last non-custom content screen, convert it to the empty screen         
 937                 mRemoveEmptyScreenRunnable = null;                                                       
 938                 mWorkspaceScreens.put(EXTRA_EMPTY_SCREEN_ID, cl);                                        
 939                 mScreenOrder.add(EXTRA_EMPTY_SCREEN_ID);                                                 
 940             }                                                                                            
 941         }                                                                                                
 942                                                                                                          
 943         if (!removeScreens.isEmpty()) {                                                                  
 944             // Update the model if we have changed any screens                                           
 945             mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder);                    
 946         }                                                                                                
 947                                                                                                          
 948         if (pageShift >= 0) {                                                                            
 949             setCurrentPage(currentPage - pageShift);                                                     
 950         }                                                                                                
 951     }                                                                                                    
 952                                                                                                          
 953     // See implementation for parameter definition.                                                      
 954     void addInScreen(View child, long container, long screenId,                                          
 955             int x, int y, int spanX, int spanY) {                                                        
 956         addInScreen(child, container, screenId, x, y, spanX, spanY, false, false);                       
 957     }                                                                                                    
 958                                                                                                          
 959     // At bind time, we use the rank (screenId) to compute x and y for hotseat items.                    
 960     // See implementation for parameter definition.                                                      
 961     void addInScreenFromBind(View child, long container, long screenId, int x, int y,                    
 962             int spanX, int spanY) {                                                                      
 963         addInScreen(child, container, screenId, x, y, spanX, spanY, false, true);                        
 964     }                                                                                                    
 965                                                                                                          
 966     // See implementation for parameter definition.                                                      
 967     void addInScreen(View child, long container, long screenId, int x, int y, int spanX, int spanY,      
 968             boolean insert) {                                                                            
 969         addInScreen(child, container, screenId, x, y, spanX, spanY, insert, false);                      
 970     }                                                                                                    
 971                                                                                                          
 972     /**                                                                                                  
 973      * Adds the specified child in the specified screen. The position and dimension of                   
 974      * the child are defined by x, y, spanX and spanY.                                                   
 975      *                                                                                                   
 976      * @param child The child to add in one of the workspace's screens.                                  
 977      * @param screenId The screen in which to add the child.                                             
 978      * @param x The X position of the child in the screen's grid.                                        
 979      * @param y The Y position of the child in the screen's grid.                                        
 980      * @param spanX The number of cells spanned horizontally by the child.                               
 981      * @param spanY The number of cells spanned vertically by the child.                                 
 982      * @param insert When true, the child is inserted at the beginning of the children list.             
 983      * @param computeXYFromRank When true, we use the rank (stored in screenId) to compute               
 984      *                          the x and y position in which to place hotseat items. Otherwise          
 985      *                          we use the x and y position to compute the rank.                         
 986      */                                                                                                  
 987     void addInScreen(View child, long container, long screenId, int x, int y, int spanX, int spanY,      
 988             boolean insert, boolean computeXYFromRank) {                                                 
 989         if (container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {                                 
 990             if (getScreenWithId(screenId) == null) {                                                     
 991                 Log.e(TAG, "Skipping child, screenId " + screenId + " not found");                       
 992                 // DEBUGGING - Print out the stack trace to see where we are adding from                 
 993                 new Throwable().printStackTrace();                                                       
 994                 return;                                                                                  
 995             }                                                                                            
 996         }                                                                                                
 997         if (screenId == EXTRA_EMPTY_SCREEN_ID) {                                                         
 998             // This should never happen                                                                  
 999             throw new RuntimeException("Screen id should not be EXTRA_EMPTY_SCREEN_ID");                 
1000         }                                                                                                
1001                                                                                                          
1002         final CellLayout layout;                                                                         
1003         if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                 
1004             layout = mLauncher.getHotseat().getLayout();                                                 
1005             child.setOnKeyListener(new HotseatIconKeyEventListener());                                   
1006                                                                                                          
1007             // Hide folder title in the hotseat                                                          
1008             if (child instanceof FolderIcon) {                                                           
1009                 ((FolderIcon) child).setTextVisible(false);                                              
1010             }                                                                                            
1011                                                                                                          
1012             if (computeXYFromRank) {                                                                     
1013                 x = mLauncher.getHotseat().getCellXFromOrder((int) screenId);                            
1014                 y = mLauncher.getHotseat().getCellYFromOrder((int) screenId);                            
1015             } else {                                                                                     
1016                 screenId = mLauncher.getHotseat().getOrderInHotseat(x, y);                               
1017             }                                                                                            
1018         } else {                                                                                         
1019             // Show folder title if not in the hotseat                                                   
1020             if (child instanceof FolderIcon) {                                                           
1021                 ((FolderIcon) child).setTextVisible(true);                                               
1022             }                                                                                            
1023             layout = getScreenWithId(screenId);                                                          
1024             child.setOnKeyListener(new IconKeyEventListener());                                          
1025         }                                                                                                
1026                                                                                                          
1027         ViewGroup.LayoutParams genericLp = child.getLayoutParams();                                      
1028         CellLayout.LayoutParams lp;                                                                      
1029         if (genericLp == null || !(genericLp instanceof CellLayout.LayoutParams)) {                      
1030             lp = new CellLayout.LayoutParams(x, y, spanX, spanY);                                        
1031         } else {                                                                                         
1032             lp = (CellLayout.LayoutParams) genericLp;                                                    
1033             lp.cellX = x;                                                                                
1034             lp.cellY = y;                                                                                
1035             lp.cellHSpan = spanX;                                                                        
1036             lp.cellVSpan = spanY;                                                                        
1037         }                                                                                                
1038                                                                                                          
1039         if (spanX < 0 && spanY < 0) {                                                                    
1040             lp.isLockedToGrid = false;                                                                   
1041         }                                                                                                
1042                                                                                                          
1043         // Get the canonical child id to uniquely represent this view in this screen                     
1044         ItemInfo info = (ItemInfo) child.getTag();                                                       
1045         int childId = mLauncher.getViewIdForItem(info);                                                  
1046                                                                                                          
1047         boolean markCellsAsOccupied = !(child instanceof Folder);                                        
1048         if (!layout.addViewToCellLayout(child, insert ? 0 : -1, childId, lp, markCellsAsOccupied)) {     
1049             // TODO: This branch occurs when the workspace is adding views                               
1050             // outside of the defined grid                                                               
1051             // maybe we should be deleting these items from the LauncherModel?                           
1052             Launcher.addDumpLog(TAG, "Failed to add to item at (" + lp.cellX + "," + lp.cellY + ") to Cel🔵
1053         }                                                                                                
1054                                                                                                          
1055         if (!(child instanceof Folder)) {                                                                
1056             child.setHapticFeedbackEnabled(false);                                                       
1057             child.setOnLongClickListener(mLongClickListener);                                            
1058         }                                                                                                
1059         if (child instanceof DropTarget) {                                                               
1060             mDragController.addDropTarget((DropTarget) child);                                           
1061         }                                                                                                
1062     }                                                                                                    
1063                                                                                                          
1064     /**                                                                                                  
1065      * Called directly from a CellLayout (not by the framework), after we've been added as a             
1066      * listener via setOnInterceptTouchEventListener(). This allows us to tell the CellLayout            
1067      * that it should intercept touch events, which is not something that is normally supported.         
1068      */                                                                                                  
1069     @Override                                                                                            
1070     public boolean onTouch(View v, MotionEvent event) {                                                  
1071         return (workspaceInModalState() || !isFinishedSwitchingState())                                  
1072                 || (!workspaceInModalState() && indexOfChild(v) != mCurrentPage);                        
1073     }                                                                                                    
1074                                                                                                          
1075     public boolean isSwitchingState() {                                                                  
1076         return mIsSwitchingState;                                                                        
1077     }                                                                                                    
1078                                                                                                          
1079     /** This differs from isSwitchingState in that we take into account how far the transition           
1080      *  has completed. */                                                                                
1081     public boolean isFinishedSwitchingState() {                                                          
1082         return !mIsSwitchingState || (mTransitionProgress > 0.5f);                                       
1083     }                                                                                                    
1084                                                                                                          
1085     protected void onWindowVisibilityChanged (int visibility) {                                          
1086         mLauncher.onWindowVisibilityChanged(visibility);                                                 
1087     }                                                                                                    
1088                                                                                                          
1089     @Override                                                                                            
1090     public boolean dispatchUnhandledMove(View focused, int direction) {                                  
1091         if (workspaceInModalState() || !isFinishedSwitchingState()) {                                    
1092             // when the home screens are shrunken, shouldn't allow side-scrolling                        
1093             return false;                                                                                
1094         }                                                                                                
1095         return super.dispatchUnhandledMove(focused, direction);                                          
1096     }                                                                                                    
1097                                                                                                          
1098     @Override                                                                                            
1099     public boolean onInterceptTouchEvent(MotionEvent ev) {                                               
1100         switch (ev.getAction() & MotionEvent.ACTION_MASK) {                                              
1101         case MotionEvent.ACTION_DOWN:                                                                    
1102             mXDown = ev.getX();                                                                          
1103             mYDown = ev.getY();                                                                          
1104             mTouchDownTime = System.currentTimeMillis();                                                 
1105             break;                                                                                       
1106         case MotionEvent.ACTION_POINTER_UP:                                                              
1107         case MotionEvent.ACTION_UP:                                                                      
1108             if (mTouchState == TOUCH_STATE_REST) {                                                       
1109                 final CellLayout currentPage = (CellLayout) getChildAt(mCurrentPage);                    
1110                 if (currentPage != null && !currentPage.lastDownOnOccupiedCell()) {                      
1111                     onWallpaperTap(ev);                                                                  
1112                 }                                                                                        
1113             }                                                                                            
1114         }                                                                                                
1115         return super.onInterceptTouchEvent(ev);                                                          
1116     }                                                                                                    
1117                                                                                                          
1118     @Override                                                                                            
1119     public boolean onGenericMotionEvent(MotionEvent event) {                                             
1120         // Ignore pointer scroll events if the custom content doesn't allow scrolling.                   
1121         if ((getScreenIdForPageIndex(getCurrentPage()) == CUSTOM_CONTENT_SCREEN_ID)                      
1122                 && (mCustomContentCallbacks != null)                                                     
1123                 && !mCustomContentCallbacks.isScrollingAllowed()) {                                      
1124             return false;                                                                                
1125         }                                                                                                
1126         return super.onGenericMotionEvent(event);                                                        
1127     }                                                                                                    
1128                                                                                                          
1129     protected void reinflateWidgetsIfNecessary() {                                                       
1130         final int clCount = getChildCount();                                                             
1131         for (int i = 0; i < clCount; i++) {                                                              
1132             CellLayout cl = (CellLayout) getChildAt(i);                                                  
1133             ShortcutAndWidgetContainer swc = cl.getShortcutsAndWidgets();                                
1134             final int itemCount = swc.getChildCount();                                                   
1135             for (int j = 0; j < itemCount; j++) {                                                        
1136                 View v = swc.getChildAt(j);                                                              
1137                                                                                                          
1138                 if (v != null  && v.getTag() instanceof LauncherAppWidgetInfo) {                         
1139                     LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) v.getTag();                     
1140                     LauncherAppWidgetHostView lahv = (LauncherAppWidgetHostView) info.hostView;          
1141                     if (lahv != null && lahv.isReinflateRequired()) {                                    
1142                         mLauncher.removeAppWidget(info);                                                 
1143                         // Remove the current widget which is inflated with the wrong orientation        
1144                         cl.removeView(lahv);                                                             
1145                         mLauncher.bindAppWidget(info);                                                   
1146                     }                                                                                    
1147                 }                                                                                        
1148             }                                                                                            
1149         }                                                                                                
1150     }                                                                                                    
1151                                                                                                          
1152     @Override                                                                                            
1153     protected void determineScrollingStart(MotionEvent ev) {                                             
1154         if (!isFinishedSwitchingState()) return;                                                         
1155                                                                                                          
1156         float deltaX = ev.getX() - mXDown;                                                               
1157         float absDeltaX = Math.abs(deltaX);                                                              
1158         float absDeltaY = Math.abs(ev.getY() - mYDown);                                                  
1159                                                                                                          
1160         if (Float.compare(absDeltaX, 0f) == 0) return;                                                   
1161                                                                                                          
1162         float slope = absDeltaY / absDeltaX;                                                             
1163         float theta = (float) Math.atan(slope);                                                          
1164                                                                                                          
1165         if (absDeltaX > mTouchSlop || absDeltaY > mTouchSlop) {                                          
1166             cancelCurrentPageLongPress();                                                                
1167         }                                                                                                
1168                                                                                                          
1169         boolean passRightSwipesToCustomContent =                                                         
1170                 (mTouchDownTime - mCustomContentShowTime) > CUSTOM_CONTENT_GESTURE_DELAY;                
1171                                                                                                          
1172         boolean swipeInIgnoreDirection = isLayoutRtl() ? deltaX < 0 : deltaX > 0;                        
1173         boolean onCustomContentScreen =                                                                  
1174                 getScreenIdForPageIndex(getCurrentPage()) == CUSTOM_CONTENT_SCREEN_ID;                   
1175         if (swipeInIgnoreDirection && onCustomContentScreen && passRightSwipesToCustomContent) {         
1176             // Pass swipes to the right to the custom content page.                                      
1177             return;                                                                                      
1178         }                                                                                                
1179                                                                                                          
1180         if (onCustomContentScreen && (mCustomContentCallbacks != null)                                   
1181                 && !mCustomContentCallbacks.isScrollingAllowed()) {                                      
1182             // Don't allow workspace scrolling if the current custom content screen doesn't allow        
1183             // scrolling.                                                                                
1184             return;                                                                                      
1185         }                                                                                                
1186                                                                                                          
1187         if (theta > MAX_SWIPE_ANGLE) {                                                                   
1188             // Above MAX_SWIPE_ANGLE, we don't want to ever start scrolling the workspace                
1189             return;                                                                                      
1190         } else if (theta > START_DAMPING_TOUCH_SLOP_ANGLE) {                                             
1191             // Above START_DAMPING_TOUCH_SLOP_ANGLE and below MAX_SWIPE_ANGLE, we want to                
1192             // increase the touch slop to make it harder to begin scrolling the workspace. This          
1193             // results in vertically scrolling widgets to more easily. The higher the angle, the         
1194             // more we increase touch slop.                                                              
1195             theta -= START_DAMPING_TOUCH_SLOP_ANGLE;                                                     
1196             float extraRatio = (float)                                                                   
1197                     Math.sqrt((theta / (MAX_SWIPE_ANGLE - START_DAMPING_TOUCH_SLOP_ANGLE)));             
1198             super.determineScrollingStart(ev, 1 + TOUCH_SLOP_DAMPING_FACTOR * extraRatio);               
1199         } else {                                                                                         
1200             // Below START_DAMPING_TOUCH_SLOP_ANGLE, we don't do anything special                        
1201             super.determineScrollingStart(ev);                                                           
1202         }                                                                                                
1203     }                                                                                                    
1204                                                                                                          
1205     protected void onPageBeginMoving() {                                                                 
1206         super.onPageBeginMoving();                                                                       
1207                                                                                                          
1208         if (isHardwareAccelerated()) {                                                                   
1209             updateChildrenLayersEnabled(false);                                                          
1210         } else {                                                                                         
1211             if (mNextPage != INVALID_PAGE) {                                                             
1212                 // we're snapping to a particular screen                                                 
1213                 enableChildrenCache(mCurrentPage, mNextPage);                                            
1214             } else {                                                                                     
1215                 // this is when user is actively dragging a particular screen, they might                
1216                 // swipe it either left or right (but we won't advance by more than one screen)          
1217                 enableChildrenCache(mCurrentPage - 1, mCurrentPage + 1);                                 
1218             }                                                                                            
1219         }                                                                                                
1220     }                                                                                                    
1221                                                                                                          
1222     protected void onPageEndMoving() {                                                                   
1223         super.onPageEndMoving();                                                                         
1224                                                                                                          
1225         if (isHardwareAccelerated()) {                                                                   
1226             updateChildrenLayersEnabled(false);                                                          
1227         } else {                                                                                         
1228             clearChildrenCache();                                                                        
1229         }                                                                                                
1230                                                                                                          
1231         if (mDragController.isDragging()) {                                                              
1232             if (workspaceInModalState()) {                                                               
1233                 // If we are in springloaded mode, then force an event to check if the current touch     
1234                 // is under a new page (to scroll to)                                                    
1235                 mDragController.forceTouchMove();                                                        
1236             }                                                                                            
1237         }                                                                                                
1238                                                                                                          
1239         if (mDelayedResizeRunnable != null) {                                                            
1240             mDelayedResizeRunnable.run();                                                                
1241             mDelayedResizeRunnable = null;                                                               
1242         }                                                                                                
1243                                                                                                          
1244         if (mDelayedSnapToPageRunnable != null) {                                                        
1245             mDelayedSnapToPageRunnable.run();                                                            
1246             mDelayedSnapToPageRunnable = null;                                                           
1247         }                                                                                                
1248         if (mStripScreensOnPageStopMoving) {                                                             
1249             stripEmptyScreens();                                                                         
1250             mStripScreensOnPageStopMoving = false;                                                       
1251         }                                                                                                
1252     }                                                                                                    
1253                                                                                                          
1254     @Override                                                                                            
1255     protected void notifyPageSwitchListener() {                                                          
1256         super.notifyPageSwitchListener();                                                                
1257         Launcher.setScreen(getNextPage());                                                               
1258                                                                                                          
1259         if (hasCustomContent() && getNextPage() == 0 && !mCustomContentShowing) {                        
1260             mCustomContentShowing = true;                                                                
1261             if (mCustomContentCallbacks != null) {                                                       
1262                 mCustomContentCallbacks.onShow(false);                                                   
1263                 mCustomContentShowTime = System.currentTimeMillis();                                     
1264                 mLauncher.updateVoiceButtonProxyVisible(false);                                          
1265             }                                                                                            
1266         } else if (hasCustomContent() && getNextPage() != 0 && mCustomContentShowing) {                  
1267             mCustomContentShowing = false;                                                               
1268             if (mCustomContentCallbacks != null) {                                                       
1269                 mCustomContentCallbacks.onHide();                                                        
1270                 mLauncher.resetQSBScroll();                                                              
1271                 mLauncher.updateVoiceButtonProxyVisible(false);                                          
1272             }                                                                                            
1273         }                                                                                                
1274     }                                                                                                    
1275                                                                                                          
1276     protected CustomContentCallbacks getCustomContentCallbacks() {                                       
1277         return mCustomContentCallbacks;                                                                  
1278     }                                                                                                    
1279                                                                                                          
1280     protected void setWallpaperDimension() {                                                             
1281         new AsyncTask<Void, Void, Void>() {                                                              
1282             public Void doInBackground(Void ... args) {                                                  
1283                 String spKey = WallpaperCropActivity.getSharedPreferencesKey();                          
1284                 SharedPreferences sp =                                                                   
1285                         mLauncher.getSharedPreferences(spKey, Context.MODE_MULTI_PROCESS);               
1286                 LauncherWallpaperPickerActivity.suggestWallpaperDimension(mLauncher.getResources(),      
1287                         sp, mLauncher.getWindowManager(), mWallpaperManager,                             
1288                         mLauncher.overrideWallpaperDimensions());                                        
1289                 return null;                                                                             
1290             }                                                                                            
1291         }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);                                
1292     }                                                                                                    
1293                                                                                                          
1294     protected void snapToPage(int whichPage, Runnable r) {                                               
1295         snapToPage(whichPage, SLOW_PAGE_SNAP_ANIMATION_DURATION, r);                                     
1296     }                                                                                                    
1297                                                                                                          
1298     protected void snapToPage(int whichPage, int duration, Runnable r) {                                 
1299         if (mDelayedSnapToPageRunnable != null) {                                                        
1300             mDelayedSnapToPageRunnable.run();                                                            
1301         }                                                                                                
1302         mDelayedSnapToPageRunnable = r;                                                                  
1303         snapToPage(whichPage, duration);                                                                 
1304     }                                                                                                    
1305                                                                                                          
1306     public void snapToScreenId(long screenId) {                                                          
1307         snapToScreenId(screenId, null);                                                                  
1308     }                                                                                                    
1309                                                                                                          
1310     protected void snapToScreenId(long screenId, Runnable r) {                                           
1311         snapToPage(getPageIndexForScreenId(screenId), r);                                                
1312     }                                                                                                    
1313                                                                                                          
1314     class WallpaperOffsetInterpolator implements Choreographer.FrameCallback {                           
1315         float mFinalOffset = 0.0f;                                                                       
1316         float mCurrentOffset = 0.5f; // to force an initial update                                       
1317         boolean mWaitingForUpdate;                                                                       
1318         Choreographer mChoreographer;                                                                    
1319         Interpolator mInterpolator;                                                                      
1320         boolean mAnimating;                                                                              
1321         long mAnimationStartTime;                                                                        
1322         float mAnimationStartOffset;                                                                     
1323         private final int ANIMATION_DURATION = 250;                                                      
1324         // Don't use all the wallpaper for parallax until you have at least this many pages              
1325         private final int MIN_PARALLAX_PAGE_SPAN = 3;                                                    
1326         int mNumScreens;                                                                                 
1327                                                                                                          
1328         public WallpaperOffsetInterpolator() {                                                           
1329             mChoreographer = Choreographer.getInstance();                                                
1330             mInterpolator = new DecelerateInterpolator(1.5f);                                            
1331         }                                                                                                
1332                                                                                                          
1333         @Override                                                                                        
1334         public void doFrame(long frameTimeNanos) {                                                       
1335             updateOffset(false);                                                                         
1336         }                                                                                                
1337                                                                                                          
1338         private void updateOffset(boolean force) {                                                       
1339             if (mWaitingForUpdate || force) {                                                            
1340                 mWaitingForUpdate = false;                                                               
1341                 if (computeScrollOffset() && mWindowToken != null) {                                     
1342                     try {                                                                                
1343                         mWallpaperManager.setWallpaperOffsets(mWindowToken,                              
1344                                 mWallpaperOffset.getCurrX(), 0.5f);                                      
1345                         setWallpaperOffsetSteps();                                                       
1346                     } catch (IllegalArgumentException e) {                                               
1347                         Log.e(TAG, "Error updating wallpaper offset: " + e);                             
1348                     }                                                                                    
1349                 }                                                                                        
1350             }                                                                                            
1351         }                                                                                                
1352                                                                                                          
1353         public boolean computeScrollOffset() {                                                           
1354             final float oldOffset = mCurrentOffset;                                                      
1355             if (mAnimating) {                                                                            
1356                 long durationSinceAnimation = System.currentTimeMillis() - mAnimationStartTime;          
1357                 float t0 = durationSinceAnimation / (float) ANIMATION_DURATION;                          
1358                 float t1 = mInterpolator.getInterpolation(t0);                                           
1359                 mCurrentOffset = mAnimationStartOffset +                                                 
1360                         (mFinalOffset - mAnimationStartOffset) * t1;                                     
1361                 mAnimating = durationSinceAnimation < ANIMATION_DURATION;                                
1362             } else {                                                                                     
1363                 mCurrentOffset = mFinalOffset;                                                           
1364             }                                                                                            
1365                                                                                                          
1366             if (Math.abs(mCurrentOffset - mFinalOffset) > 0.0000001f) {                                  
1367                 scheduleUpdate();                                                                        
1368             }                                                                                            
1369             if (Math.abs(oldOffset - mCurrentOffset) > 0.0000001f) {                                     
1370                 return true;                                                                             
1371             }                                                                                            
1372             return false;                                                                                
1373         }                                                                                                
1374                                                                                                          
1375         private float wallpaperOffsetForCurrentScroll() {                                                
1376             if (getChildCount() <= 1) {                                                                  
1377                 return 0;                                                                                
1378             }                                                                                            
1379                                                                                                          
1380             // Exclude the leftmost page                                                                 
1381             int emptyExtraPages = numEmptyScreensToIgnore();                                             
1382             int firstIndex = numCustomPages();                                                           
1383             // Exclude the last extra empty screen (if we have > MIN_PARALLAX_PAGE_SPAN pages)           
1384             int lastIndex = getChildCount() - 1 - emptyExtraPages;                                       
1385             if (isLayoutRtl()) {                                                                         
1386                 int temp = firstIndex;                                                                   
1387                 firstIndex = lastIndex;                                                                  
1388                 lastIndex = temp;                                                                        
1389             }                                                                                            
1390                                                                                                          
1391             int firstPageScrollX = getScrollForPage(firstIndex);                                         
1392             int scrollRange = getScrollForPage(lastIndex) - firstPageScrollX;                            
1393             if (scrollRange == 0) {                                                                      
1394                 return 0;                                                                                
1395             } else {                                                                                     
1396                 // TODO: do different behavior if it's  a live wallpaper?                                
1397                 // Sometimes the left parameter of the pages is animated during a layout transition;     
1398                 // this parameter offsets it to keep the wallpaper from animating as well                
1399                 int adjustedScroll =                                                                     
1400                         getScrollX() - firstPageScrollX - getLayoutTransitionOffsetForPage(0);           
1401                 float offset = Math.min(1, adjustedScroll / (float) scrollRange);                        
1402                 offset = Math.max(0, offset);                                                            
1403                 // Don't use up all the wallpaper parallax until you have at least                       
1404                 // MIN_PARALLAX_PAGE_SPAN pages                                                          
1405                 int numScrollingPages = getNumScreensExcludingEmptyAndCustom();                          
1406                 int parallaxPageSpan;                                                                    
1407                 if (mWallpaperIsLiveWallpaper) {                                                         
1408                     parallaxPageSpan = numScrollingPages - 1;                                            
1409                 } else {                                                                                 
1410                     parallaxPageSpan = Math.max(MIN_PARALLAX_PAGE_SPAN, numScrollingPages - 1);          
1411                 }                                                                                        
1412                 mNumPagesForWallpaperParallax = parallaxPageSpan;                                        
1413                                                                                                          
1414                 // On RTL devices, push the wallpaper offset to the right if we don't have enough        
1415                 // pages (ie if numScrollingPages < MIN_PARALLAX_PAGE_SPAN)                              
1416                 int padding = isLayoutRtl() ? parallaxPageSpan - numScrollingPages + 1 : 0;              
1417                 return offset * (padding + numScrollingPages - 1) / parallaxPageSpan;                    
1418             }                                                                                            
1419         }                                                                                                
1420                                                                                                          
1421         private int numEmptyScreensToIgnore() {                                                          
1422             int numScrollingPages = getChildCount() - numCustomPages();                                  
1423             if (numScrollingPages >= MIN_PARALLAX_PAGE_SPAN && hasExtraEmptyScreen()) {                  
1424                 return 1;                                                                                
1425             } else {                                                                                     
1426                 return 0;                                                                                
1427             }                                                                                            
1428         }                                                                                                
1429                                                                                                          
1430         private int getNumScreensExcludingEmptyAndCustom() {                                             
1431             int numScrollingPages = getChildCount() - numEmptyScreensToIgnore() - numCustomPages();      
1432             return numScrollingPages;                                                                    
1433         }                                                                                                
1434                                                                                                          
1435         public void syncWithScroll() {                                                                   
1436             float offset = wallpaperOffsetForCurrentScroll();                                            
1437             mWallpaperOffset.setFinalX(offset);                                                          
1438             updateOffset(true);                                                                          
1439         }                                                                                                
1440                                                                                                          
1441         public float getCurrX() {                                                                        
1442             return mCurrentOffset;                                                                       
1443         }                                                                                                
1444                                                                                                          
1445         public float getFinalX() {                                                                       
1446             return mFinalOffset;                                                                         
1447         }                                                                                                
1448                                                                                                          
1449         private void animateToFinal() {                                                                  
1450             mAnimating = true;                                                                           
1451             mAnimationStartOffset = mCurrentOffset;                                                      
1452             mAnimationStartTime = System.currentTimeMillis();                                            
1453         }                                                                                                
1454                                                                                                          
1455         private void setWallpaperOffsetSteps() {                                                         
1456             // Set wallpaper offset steps (1 / (number of screens - 1))                                  
1457             float xOffset = 1.0f / mNumPagesForWallpaperParallax;                                        
1458             if (xOffset != mLastSetWallpaperOffsetSteps) {                                               
1459                 mWallpaperManager.setWallpaperOffsetSteps(xOffset, 1.0f);                                
1460                 mLastSetWallpaperOffsetSteps = xOffset;                                                  
1461             }                                                                                            
1462         }                                                                                                
1463                                                                                                          
1464         public void setFinalX(float x) {                                                                 
1465             scheduleUpdate();                                                                            
1466             mFinalOffset = Math.max(0f, Math.min(x, 1.0f));                                              
1467             if (getNumScreensExcludingEmptyAndCustom() != mNumScreens) {                                 
1468                 if (mNumScreens > 0) {                                                                   
1469                     // Don't animate if we're going from 0 screens                                       
1470                     animateToFinal();                                                                    
1471                 }                                                                                        
1472                 mNumScreens = getNumScreensExcludingEmptyAndCustom();                                    
1473             }                                                                                            
1474         }                                                                                                
1475                                                                                                          
1476         private void scheduleUpdate() {                                                                  
1477             if (!mWaitingForUpdate) {                                                                    
1478                 mChoreographer.postFrameCallback(this);                                                  
1479                 mWaitingForUpdate = true;                                                                
1480             }                                                                                            
1481         }                                                                                                
1482                                                                                                          
1483         public void jumpToFinal() {                                                                      
1484             mCurrentOffset = mFinalOffset;                                                               
1485         }                                                                                                
1486     }                                                                                                    
1487                                                                                                          
1488     @Override                                                                                            
1489     public void computeScroll() {                                                                        
1490         super.computeScroll();                                                                           
1491         mWallpaperOffset.syncWithScroll();                                                               
1492     }                                                                                                    
1493                                                                                                          
1494     @Override                                                                                            
1495     public void announceForAccessibility(CharSequence text) {                                            
1496         // Don't announce if apps is on top of us.                                                       
1497         if (!mLauncher.isAllAppsVisible()) {                                                             
1498             super.announceForAccessibility(text);                                                        
1499         }                                                                                                
1500     }                                                                                                    
1501                                                                                                          
1502     void showOutlines() {                                                                                
1503         if (!workspaceInModalState() && !mIsSwitchingState) {                                            
1504             if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();     
1505             if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();       
1506             mChildrenOutlineFadeInAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 1.0🔵
1507             mChildrenOutlineFadeInAnimation.setDuration(CHILDREN_OUTLINE_FADE_IN_DURATION);              
1508             mChildrenOutlineFadeInAnimation.start();                                                     
1509         }                                                                                                
1510     }                                                                                                    
1511                                                                                                          
1512     void hideOutlines() {                                                                                
1513         if (!workspaceInModalState() && !mIsSwitchingState) {                                            
1514             if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();       
1515             if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();     
1516             mChildrenOutlineFadeOutAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 0.🔵
1517             mChildrenOutlineFadeOutAnimation.setDuration(CHILDREN_OUTLINE_FADE_OUT_DURATION);            
1518             mChildrenOutlineFadeOutAnimation.setStartDelay(CHILDREN_OUTLINE_FADE_OUT_DELAY);             
1519             mChildrenOutlineFadeOutAnimation.start();                                                    
1520         }                                                                                                
1521     }                                                                                                    
1522                                                                                                          
1523     public void showOutlinesTemporarily() {                                                              
1524         if (!mIsPageMoving && !isTouchActive()) {                                                        
1525             snapToPage(mCurrentPage);                                                                    
1526         }                                                                                                
1527     }                                                                                                    
1528                                                                                                          
1529     public void setChildrenOutlineAlpha(float alpha) {                                                   
1530         mChildrenOutlineAlpha = alpha;                                                                   
1531         for (int i = 0; i < getChildCount(); i++) {                                                      
1532             CellLayout cl = (CellLayout) getChildAt(i);                                                  
1533             cl.setBackgroundAlpha(alpha);                                                                
1534         }                                                                                                
1535     }                                                                                                    
1536                                                                                                          
1537     public float getChildrenOutlineAlpha() {                                                             
1538         return mChildrenOutlineAlpha;                                                                    
1539     }                                                                                                    
1540                                                                                                          
1541     private void animateBackgroundGradient(float finalAlpha, boolean animated) {                         
1542         final DragLayer dragLayer = mLauncher.getDragLayer();                                            
1543                                                                                                          
1544         if (mBackgroundFadeInAnimation != null) {                                                        
1545             mBackgroundFadeInAnimation.cancel();                                                         
1546             mBackgroundFadeInAnimation = null;                                                           
1547         }                                                                                                
1548         if (mBackgroundFadeOutAnimation != null) {                                                       
1549             mBackgroundFadeOutAnimation.cancel();                                                        
1550             mBackgroundFadeOutAnimation = null;                                                          
1551         }                                                                                                
1552         float startAlpha = dragLayer.getBackgroundAlpha();                                               
1553         if (finalAlpha != startAlpha) {                                                                  
1554             if (animated) {                                                                              
1555                 mBackgroundFadeOutAnimation =                                                            
1556                         LauncherAnimUtils.ofFloat(this, startAlpha, finalAlpha);                         
1557                 mBackgroundFadeOutAnimation.addUpdateListener(new AnimatorUpdateListener() {             
1558                     public void onAnimationUpdate(ValueAnimator animation) {                             
1559                         dragLayer.setBackgroundAlpha(                                                    
1560                                 ((Float)animation.getAnimatedValue()).floatValue());                     
1561                     }                                                                                    
1562                 });                                                                                      
1563                 mBackgroundFadeOutAnimation.setInterpolator(new DecelerateInterpolator(1.5f));           
1564                 mBackgroundFadeOutAnimation.setDuration(BACKGROUND_FADE_OUT_DURATION);                   
1565                 mBackgroundFadeOutAnimation.start();                                                     
1566             } else {                                                                                     
1567                 dragLayer.setBackgroundAlpha(finalAlpha);                                                
1568             }                                                                                            
1569         }                                                                                                
1570     }                                                                                                    
1571                                                                                                          
1572     float backgroundAlphaInterpolator(float r) {                                                         
1573         float pivotA = 0.1f;                                                                             
1574         float pivotB = 0.4f;                                                                             
1575         if (r < pivotA) {                                                                                
1576             return 0;                                                                                    
1577         } else if (r > pivotB) {                                                                         
1578             return 1.0f;                                                                                 
1579         } else {                                                                                         
1580             return (r - pivotA)/(pivotB - pivotA);                                                       
1581         }                                                                                                
1582     }                                                                                                    
1583                                                                                                          
1584     private void updatePageAlphaValues(int screenCenter) {                                               
1585         boolean isInOverscroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX;                         
1586         if (mWorkspaceFadeInAdjacentScreens &&                                                           
1587                 !workspaceInModalState() &&                                                              
1588                 !mIsSwitchingState &&                                                                    
1589                 !isInOverscroll) {                                                                       
1590             for (int i = numCustomPages(); i < getChildCount(); i++) {                                   
1591                 CellLayout child = (CellLayout) getChildAt(i);                                           
1592                 if (child != null) {                                                                     
1593                     float scrollProgress = getScrollProgress(screenCenter, child, i);                    
1594                     float alpha = 1 - Math.abs(scrollProgress);                                          
1595                     child.getShortcutsAndWidgets().setAlpha(alpha);                                      
1596                     //child.setBackgroundAlphaMultiplier(1 - alpha);                                     
1597                 }                                                                                        
1598             }                                                                                            
1599         }                                                                                                
1600     }                                                                                                    
1601                                                                                                          
1602     private void setChildrenBackgroundAlphaMultipliers(float a) {                                        
1603         for (int i = 0; i < getChildCount(); i++) {                                                      
1604             CellLayout child = (CellLayout) getChildAt(i);                                               
1605             child.setBackgroundAlphaMultiplier(a);                                                       
1606         }                                                                                                
1607     }                                                                                                    
1608                                                                                                          
1609     public boolean hasCustomContent() {                                                                  
1610         return (mScreenOrder.size() > 0 && mScreenOrder.get(0) == CUSTOM_CONTENT_SCREEN_ID);             
1611     }                                                                                                    
1612                                                                                                          
1613     public int numCustomPages() {                                                                        
1614         return hasCustomContent() ? 1 : 0;                                                               
1615     }                                                                                                    
1616                                                                                                          
1617     public boolean isOnOrMovingToCustomContent() {                                                       
1618         return hasCustomContent() && getNextPage() == 0;                                                 
1619     }                                                                                                    
1620                                                                                                          
1621     private void updateStateForCustomContent(int screenCenter) {                                         
1622         float translationX = 0;                                                                          
1623         float progress = 0;                                                                              
1624         if (hasCustomContent()) {                                                                        
1625             int index = mScreenOrder.indexOf(CUSTOM_CONTENT_SCREEN_ID);                                  
1626                                                                                                          
1627             int scrollDelta = getScrollX() - getScrollForPage(index) -                                   
1628                     getLayoutTransitionOffsetForPage(index);                                             
1629             float scrollRange = getScrollForPage(index + 1) - getScrollForPage(index);                   
1630             translationX = scrollRange - scrollDelta;                                                    
1631             progress = (scrollRange - scrollDelta) / scrollRange;                                        
1632                                                                                                          
1633             if (isLayoutRtl()) {                                                                         
1634                 translationX = Math.min(0, translationX);                                                
1635             } else {                                                                                     
1636                 translationX = Math.max(0, translationX);                                                
1637             }                                                                                            
1638             progress = Math.max(0, progress);                                                            
1639         }                                                                                                
1640                                                                                                          
1641         if (Float.compare(progress, mLastCustomContentScrollProgress) == 0) return;                      
1642                                                                                                          
1643         CellLayout cc = mWorkspaceScreens.get(CUSTOM_CONTENT_SCREEN_ID);                                 
1644         if (progress > 0 && cc.getVisibility() != VISIBLE && !workspaceInModalState()) {                 
1645             cc.setVisibility(VISIBLE);                                                                   
1646         }                                                                                                
1647                                                                                                          
1648         mLastCustomContentScrollProgress = progress;                                                     
1649                                                                                                          
1650         mLauncher.getDragLayer().setBackgroundAlpha(progress * 0.8f);                                    
1651                                                                                                          
1652         if (mLauncher.getHotseat() != null) {                                                            
1653             mLauncher.getHotseat().setTranslationX(translationX);                                        
1654         }                                                                                                
1655                                                                                                          
1656         if (getPageIndicator() != null) {                                                                
1657             getPageIndicator().setTranslationX(translationX);                                            
1658         }                                                                                                
1659                                                                                                          
1660         if (mCustomContentCallbacks != null) {                                                           
1661             mCustomContentCallbacks.onScrollProgressChanged(progress);                                   
1662         }                                                                                                
1663     }                                                                                                    
1664                                                                                                          
1665     @Override                                                                                            
1666     protected OnClickListener getPageIndicatorClickListener() {                                          
1667         AccessibilityManager am = (AccessibilityManager)                                                 
1668                 getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);                            
1669         if (!am.isTouchExplorationEnabled()) {                                                           
1670             return null;                                                                                 
1671         }                                                                                                
1672         OnClickListener listener = new OnClickListener() {                                               
1673             @Override                                                                                    
1674             public void onClick(View arg0) {                                                             
1675                 enterOverviewMode();                                                                     
1676             }                                                                                            
1677         };                                                                                               
1678         return listener;                                                                                 
1679     }                                                                                                    
1680                                                                                                          
1681     @Override                                                                                            
1682     protected void screenScrolled(int screenCenter) {                                                    
1683         final boolean isRtl = isLayoutRtl();                                                             
1684         super.screenScrolled(screenCenter);                                                              
1685                                                                                                          
1686         updatePageAlphaValues(screenCenter);                                                             
1687         updateStateForCustomContent(screenCenter);                                                       
1688         enableHwLayersOnVisiblePages();                                                                  
1689                                                                                                          
1690         boolean shouldOverScroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX;                       
1691                                                                                                          
1692         if (shouldOverScroll) {                                                                          
1693             int index = 0;                                                                               
1694             final int lowerIndex = 0;                                                                    
1695             final int upperIndex = getChildCount() - 1;                                                  
1696                                                                                                          
1697             final boolean isLeftPage = mOverScrollX < 0;                                                 
1698             index = (!isRtl && isLeftPage) || (isRtl && !isLeftPage) ? lowerIndex : upperIndex;          
1699                                                                                                          
1700             CellLayout cl = (CellLayout) getChildAt(index);                                              
1701             float effect = Math.abs(mOverScrollEffect);                                                  
1702             cl.setOverScrollAmount(Math.abs(effect), isLeftPage);                                        
1703                                                                                                          
1704             mOverscrollEffectSet = true;                                                                 
1705         } else {                                                                                         
1706             if (mOverscrollEffectSet && getChildCount() > 0) {                                           
1707                 mOverscrollEffectSet = false;                                                            
1708                 ((CellLayout) getChildAt(0)).setOverScrollAmount(0, false);                              
1709                 ((CellLayout) getChildAt(getChildCount() - 1)).setOverScrollAmount(0, false);            
1710             }                                                                                            
1711         }                                                                                                
1712     }                                                                                                    
1713                                                                                                          
1714     @Override                                                                                            
1715     protected void overScroll(float amount) {                                                            
1716         boolean shouldOverScroll = (amount < 0 && (!hasCustomContent() || isLayoutRtl())) ||             
1717                 (amount > 0 && (!hasCustomContent() || !isLayoutRtl()));                                 
1718         if (shouldOverScroll) {                                                                          
1719             dampedOverScroll(amount);                                                                    
1720             mOverScrollEffect = acceleratedOverFactor(amount);                                           
1721         } else {                                                                                         
1722             mOverScrollEffect = 0;                                                                       
1723         }                                                                                                
1724     }                                                                                                    
1725                                                                                                          
1726     protected void onAttachedToWindow() {                                                                
1727         super.onAttachedToWindow();                                                                      
1728         mWindowToken = getWindowToken();                                                                 
1729         computeScroll();                                                                                 
1730         mDragController.setWindowToken(mWindowToken);                                                    
1731     }                                                                                                    
1732                                                                                                          
1733     protected void onDetachedFromWindow() {                                                              
1734         super.onDetachedFromWindow();                                                                    
1735         mWindowToken = null;                                                                             
1736     }                                                                                                    
1737                                                                                                          
1738     protected void onResume() {                                                                          
1739         if (getPageIndicator() != null) {                                                                
1740             // In case accessibility state has changed, we need to perform this on every                 
1741             // attach to window                                                                          
1742             OnClickListener listener = getPageIndicatorClickListener();                                  
1743             if (listener != null) {                                                                      
1744                 getPageIndicator().setOnClickListener(listener);                                         
1745             }                                                                                            
1746         }                                                                                                
1747         AccessibilityManager am = (AccessibilityManager)                                                 
1748                 getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);                            
1749         sAccessibilityEnabled = am.isEnabled();                                                          
1750                                                                                                          
1751         // Update wallpaper dimensions if they were changed since last onResume                          
1752         // (we also always set the wallpaper dimensions in the constructor)                              
1753         if (LauncherAppState.getInstance().hasWallpaperChangedSinceLastCheck()) {                        
1754             setWallpaperDimension();                                                                     
1755         }                                                                                                
1756         mWallpaperIsLiveWallpaper = mWallpaperManager.getWallpaperInfo() != null;                        
1757         // Force the wallpaper offset steps to be set again, because another app might have changed      
1758         // them                                                                                          
1759         mLastSetWallpaperOffsetSteps = 0f;                                                               
1760     }                                                                                                    
1761                                                                                                          
1762     @Override                                                                                            
1763     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {                 
1764         if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) {                       
1765             mWallpaperOffset.syncWithScroll();                                                           
1766             mWallpaperOffset.jumpToFinal();                                                              
1767         }                                                                                                
1768         super.onLayout(changed, left, top, right, bottom);                                               
1769     }                                                                                                    
1770                                                                                                          
1771     @Override                                                                                            
1772     protected void onDraw(Canvas canvas) {                                                               
1773         super.onDraw(canvas);                                                                            
1774                                                                                                          
1775         // Call back to LauncherModel to finish binding after the first draw                             
1776         post(mBindPages);                                                                                
1777     }                                                                                                    
1778                                                                                                          
1779     @Override                                                                                            
1780     protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {           
1781         if (!mLauncher.isAllAppsVisible()) {                                                             
1782             final Folder openFolder = getOpenFolder();                                                   
1783             if (openFolder != null) {                                                                    
1784                 return openFolder.requestFocus(direction, previouslyFocusedRect);                        
1785             } else {                                                                                     
1786                 return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);              
1787             }                                                                                            
1788         }                                                                                                
1789         return false;                                                                                    
1790     }                                                                                                    
1791                                                                                                          
1792     @Override                                                                                            
1793     public int getDescendantFocusability() {                                                             
1794         if (workspaceInModalState()) {                                                                   
1795             return ViewGroup.FOCUS_BLOCK_DESCENDANTS;                                                    
1796         }                                                                                                
1797         return super.getDescendantFocusability();                                                        
1798     }                                                                                                    
1799                                                                                                          
1800     @Override                                                                                            
1801     public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {                 
1802         if (!mLauncher.isAllAppsVisible()) {                                                             
1803             final Folder openFolder = getOpenFolder();                                                   
1804             if (openFolder != null) {                                                                    
1805                 openFolder.addFocusables(views, direction);                                              
1806             } else {                                                                                     
1807                 super.addFocusables(views, direction, focusableMode);                                    
1808             }                                                                                            
1809         }                                                                                                
1810     }                                                                                                    
1811                                                                                                          
1812     public boolean workspaceInModalState() {                                                             
1813         return mState != State.NORMAL;                                                                   
1814     }                                                                                                    
1815                                                                                                          
1816     void enableChildrenCache(int fromPage, int toPage) {                                                 
1817         if (fromPage > toPage) {                                                                         
1818             final int temp = fromPage;                                                                   
1819             fromPage = toPage;                                                                           
1820             toPage = temp;                                                                               
1821         }                                                                                                
1822                                                                                                          
1823         final int screenCount = getChildCount();                                                         
1824                                                                                                          
1825         fromPage = Math.max(fromPage, 0);                                                                
1826         toPage = Math.min(toPage, screenCount - 1);                                                      
1827                                                                                                          
1828         for (int i = fromPage; i <= toPage; i++) {                                                       
1829             final CellLayout layout = (CellLayout) getChildAt(i);                                        
1830             layout.setChildrenDrawnWithCacheEnabled(true);                                               
1831             layout.setChildrenDrawingCacheEnabled(true);                                                 
1832         }                                                                                                
1833     }                                                                                                    
1834                                                                                                          
1835     void clearChildrenCache() {                                                                          
1836         final int screenCount = getChildCount();                                                         
1837         for (int i = 0; i < screenCount; i++) {                                                          
1838             final CellLayout layout = (CellLayout) getChildAt(i);                                        
1839             layout.setChildrenDrawnWithCacheEnabled(false);                                              
1840             // In software mode, we don't want the items to continue to be drawn into bitmaps            
1841             if (!isHardwareAccelerated()) {                                                              
1842                 layout.setChildrenDrawingCacheEnabled(false);                                            
1843             }                                                                                            
1844         }                                                                                                
1845     }                                                                                                    
1846                                                                                                          
1847     private void updateChildrenLayersEnabled(boolean force) {                                            
1848         boolean small = mState == State.OVERVIEW || mIsSwitchingState;                                   
1849         boolean enableChildrenLayers = force || small || mAnimatingViewIntoPlace || isPageMoving();      
1850                                                                                                          
1851         if (enableChildrenLayers != mChildrenLayersEnabled) {                                            
1852             mChildrenLayersEnabled = enableChildrenLayers;                                               
1853             if (mChildrenLayersEnabled) {                                                                
1854                 enableHwLayersOnVisiblePages();                                                          
1855             } else {                                                                                     
1856                 for (int i = 0; i < getPageCount(); i++) {                                               
1857                     final CellLayout cl = (CellLayout) getChildAt(i);                                    
1858                     cl.enableHardwareLayer(false);                                                       
1859                 }                                                                                        
1860             }                                                                                            
1861         }                                                                                                
1862     }                                                                                                    
1863                                                                                                          
1864     private void enableHwLayersOnVisiblePages() {                                                        
1865         if (mChildrenLayersEnabled) {                                                                    
1866             final int screenCount = getChildCount();                                                     
1867             getVisiblePages(mTempVisiblePagesRange);                                                     
1868             int leftScreen = mTempVisiblePagesRange[0];                                                  
1869             int rightScreen = mTempVisiblePagesRange[1];                                                 
1870             if (leftScreen == rightScreen) {                                                             
1871                 // make sure we're caching at least two pages always                                     
1872                 if (rightScreen < screenCount - 1) {                                                     
1873                     rightScreen++;                                                                       
1874                 } else if (leftScreen > 0) {                                                             
1875                     leftScreen--;                                                                        
1876                 }                                                                                        
1877             }                                                                                            
1878                                                                                                          
1879             final CellLayout customScreen = mWorkspaceScreens.get(CUSTOM_CONTENT_SCREEN_ID);             
1880             for (int i = 0; i < screenCount; i++) {                                                      
1881                 final CellLayout layout = (CellLayout) getPageAt(i);                                     
1882                                                                                                          
1883                 // enable layers between left and right screen inclusive, except for the                 
1884                 // customScreen, which may animate its content during transitions.                       
1885                 boolean enableLayer = layout != customScreen &&                                          
1886                         leftScreen <= i && i <= rightScreen && shouldDrawChild(layout);                  
1887                 layout.enableHardwareLayer(enableLayer);                                                 
1888             }                                                                                            
1889         }                                                                                                
1890     }                                                                                                    
1891                                                                                                          
1892     public void buildPageHardwareLayers() {                                                              
1893         // force layers to be enabled just for the call to buildLayer                                    
1894         updateChildrenLayersEnabled(true);                                                               
1895         if (getWindowToken() != null) {                                                                  
1896             final int childCount = getChildCount();                                                      
1897             for (int i = 0; i < childCount; i++) {                                                       
1898                 CellLayout cl = (CellLayout) getChildAt(i);                                              
1899                 cl.buildHardwareLayer();                                                                 
1900             }                                                                                            
1901         }                                                                                                
1902         updateChildrenLayersEnabled(false);                                                              
1903     }                                                                                                    
1904                                                                                                          
1905     protected void onWallpaperTap(MotionEvent ev) {                                                      
1906         final int[] position = mTempCell;                                                                
1907         getLocationOnScreen(position);                                                                   
1908                                                                                                          
1909         int pointerIndex = ev.getActionIndex();                                                          
1910         position[0] += (int) ev.getX(pointerIndex);                                                      
1911         position[1] += (int) ev.getY(pointerIndex);                                                      
1912                                                                                                          
1913         mWallpaperManager.sendWallpaperCommand(getWindowToken(),                                         
1914                 ev.getAction() == MotionEvent.ACTION_UP                                                  
1915                         ? WallpaperManager.COMMAND_TAP : WallpaperManager.COMMAND_SECONDARY_TAP,         
1916                 position[0], position[1], 0, null);                                                      
1917     }                                                                                                    
1918                                                                                                          
1919     /*                                                                                                   
1920      * This interpolator emulates the rate at which the perceived scale of an object changes             
1921      * as its distance from a camera increases. When this interpolator is applied to a scale             
1922      * animation on a view, it evokes the sense that the object is shrinking due to moving away          
1923      * from the camera.                                                                                  
1924      */                                                                                                  
1925     static class ZInterpolator implements TimeInterpolator {                                             
1926         private float focalLength;                                                                       
1927                                                                                                          
1928         public ZInterpolator(float foc) {                                                                
1929             focalLength = foc;                                                                           
1930         }                                                                                                
1931                                                                                                          
1932         public float getInterpolation(float input) {                                                     
1933             return (1.0f - focalLength / (focalLength + input)) /                                        
1934                 (1.0f - focalLength / (focalLength + 1.0f));                                             
1935         }                                                                                                
1936     }                                                                                                    
1937                                                                                                          
1938     /*                                                                                                   
1939      * The exact reverse of ZInterpolator.                                                               
1940      */                                                                                                  
1941     static class InverseZInterpolator implements TimeInterpolator {                                      
1942         private ZInterpolator zInterpolator;                                                             
1943         public InverseZInterpolator(float foc) {                                                         
1944             zInterpolator = new ZInterpolator(foc);                                                      
1945         }                                                                                                
1946         public float getInterpolation(float input) {                                                     
1947             return 1 - zInterpolator.getInterpolation(1 - input);                                        
1948         }                                                                                                
1949     }                                                                                                    
1950                                                                                                          
1951     /*                                                                                                   
1952      * ZInterpolator compounded with an ease-out.                                                        
1953      */                                                                                                  
1954     static class ZoomOutInterpolator implements TimeInterpolator {                                       
1955         private final DecelerateInterpolator decelerate = new DecelerateInterpolator(0.75f);             
1956         private final ZInterpolator zInterpolator = new ZInterpolator(0.13f);                            
1957                                                                                                          
1958         public float getInterpolation(float input) {                                                     
1959             return decelerate.getInterpolation(zInterpolator.getInterpolation(input));                   
1960         }                                                                                                
1961     }                                                                                                    
1962                                                                                                          
1963     /*                                                                                                   
1964      * InvereZInterpolator compounded with an ease-out.                                                  
1965      */                                                                                                  
1966     static class ZoomInInterpolator implements TimeInterpolator {                                        
1967         private final InverseZInterpolator inverseZInterpolator = new InverseZInterpolator(0.35f);       
1968         private final DecelerateInterpolator decelerate = new DecelerateInterpolator(3.0f);              
1969                                                                                                          
1970         public float getInterpolation(float input) {                                                     
1971             return decelerate.getInterpolation(inverseZInterpolator.getInterpolation(input));            
1972         }                                                                                                
1973     }                                                                                                    
1974                                                                                                          
1975     private final ZoomInInterpolator mZoomInInterpolator = new ZoomInInterpolator();                     
1976                                                                                                          
1977     /*                                                                                                   
1978     *                                                                                                    
1979     * We call these methods (onDragStartedWithItemSpans/onDragStartedWithSize) whenever we               
1980     * start a drag in Launcher, regardless of whether the drag has ever entered the Workspace            
1981     *                                                                                                    
1982     * These methods mark the appropriate pages as accepting drops (which alters their visual             
1983     * appearance).                                                                                       
1984     *                                                                                                    
1985     */                                                                                                   
1986     private static Rect getDrawableBounds(Drawable d) {                                                  
1987         Rect bounds = new Rect();                                                                        
1988         d.copyBounds(bounds);                                                                            
1989         if (bounds.width() == 0 || bounds.height() == 0) {                                               
1990             bounds.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());                             
1991         } else {                                                                                         
1992             bounds.offsetTo(0, 0);                                                                       
1993         }                                                                                                
1994         if (d instanceof PreloadIconDrawable) {                                                          
1995             int inset = -((PreloadIconDrawable) d).getOutset();                                          
1996             bounds.inset(inset, inset);                                                                  
1997         }                                                                                                
1998         return bounds;                                                                                   
1999     }                                                                                                    
2000                                                                                                          
2001     public void onExternalDragStartedWithItem(View v) {                                                  
2002         // Compose a drag bitmap with the view scaled to the icon size                                   
2003         LauncherAppState app = LauncherAppState.getInstance();                                           
2004         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                    
2005         int iconSize = grid.iconSizePx;                                                                  
2006         int bmpWidth = v.getMeasuredWidth();                                                             
2007         int bmpHeight = v.getMeasuredHeight();                                                           
2008                                                                                                          
2009         // If this is a text view, use its drawable instead                                              
2010         if (v instanceof TextView) {                                                                     
2011             TextView tv = (TextView) v;                                                                  
2012             Drawable d = tv.getCompoundDrawables()[1];                                                   
2013             Rect bounds = getDrawableBounds(d);                                                          
2014             bmpWidth = bounds.width();                                                                   
2015             bmpHeight = bounds.height();                                                                 
2016         }                                                                                                
2017                                                                                                          
2018         // Compose the bitmap to create the icon from                                                    
2019         Bitmap b = Bitmap.createBitmap(bmpWidth, bmpHeight,                                              
2020                 Bitmap.Config.ARGB_8888);                                                                
2021         mCanvas.setBitmap(b);                                                                            
2022         drawDragView(v, mCanvas, 0);                                                                     
2023         mCanvas.setBitmap(null);                                                                         
2024                                                                                                          
2025         // The outline is used to visualize where the item will land if dropped                          
2026         mDragOutline = createDragOutline(b, DRAG_BITMAP_PADDING, iconSize, iconSize, true);              
2027     }                                                                                                    
2028                                                                                                          
2029     public void onDragStartedWithItem(PendingAddItemInfo info, Bitmap b, boolean clipAlpha) {            
2030         int[] size = estimateItemSize(info.spanX, info.spanY, info, false);                              
2031                                                                                                          
2032         // The outline is used to visualize where the item will land if dropped                          
2033         mDragOutline = createDragOutline(b, DRAG_BITMAP_PADDING, size[0], size[1], clipAlpha);           
2034     }                                                                                                    
2035                                                                                                          
2036     public void exitWidgetResizeMode() {                                                                 
2037         DragLayer dragLayer = mLauncher.getDragLayer();                                                  
2038         dragLayer.clearAllResizeFrames();                                                                
2039     }                                                                                                    
2040                                                                                                          
2041     private void initAnimationArrays() {                                                                 
2042         final int childCount = getChildCount();                                                          
2043         if (mLastChildCount == childCount) return;                                                       
2044                                                                                                          
2045         mOldBackgroundAlphas = new float[childCount];                                                    
2046         mOldAlphas = new float[childCount];                                                              
2047         mNewBackgroundAlphas = new float[childCount];                                                    
2048         mNewAlphas = new float[childCount];                                                              
2049     }                                                                                                    
2050                                                                                                          
2051     Animator getChangeStateAnimation(final State state, boolean animated,                                
2052             ArrayList<View> layerViews) {                                                                
2053         return getChangeStateAnimation(state, animated, 0, -1, layerViews);                              
2054     }                                                                                                    
2055                                                                                                          
2056     @Override                                                                                            
2057     protected void getFreeScrollPageRange(int[] range) {                                                 
2058         getOverviewModePages(range);                                                                     
2059     }                                                                                                    
2060                                                                                                          
2061     private void getOverviewModePages(int[] range) {                                                     
2062         int start = numCustomPages();                                                                    
2063         int end = getChildCount() - 1;                                                                   
2064                                                                                                          
2065         range[0] = Math.max(0, Math.min(start, getChildCount() - 1));                                    
2066         range[1] = Math.max(0,  end);                                                                    
2067     }                                                                                                    
2068                                                                                                          
2069     protected void onStartReordering() {                                                                 
2070         super.onStartReordering();                                                                       
2071         showOutlines();                                                                                  
2072         // Reordering handles its own animations, disable the automatic ones.                            
2073         disableLayoutTransitions();                                                                      
2074     }                                                                                                    
2075                                                                                                          
2076     protected void onEndReordering() {                                                                   
2077         super.onEndReordering();                                                                         
2078                                                                                                          
2079         if (mLauncher.isWorkspaceLoading()) {                                                            
2080             // Invalid and dangerous operation if workspace is loading                                   
2081             return;                                                                                      
2082         }                                                                                                
2083                                                                                                          
2084         hideOutlines();                                                                                  
2085         mScreenOrder.clear();                                                                            
2086         int count = getChildCount();                                                                     
2087         for (int i = 0; i < count; i++) {                                                                
2088             CellLayout cl = ((CellLayout) getChildAt(i));                                                
2089             mScreenOrder.add(getIdForScreen(cl));                                                        
2090         }                                                                                                
2091                                                                                                          
2092         mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder);                        
2093                                                                                                          
2094         // Re-enable auto layout transitions for page deletion.                                          
2095         enableLayoutTransitions();                                                                       
2096     }                                                                                                    
2097                                                                                                          
2098     public boolean isInOverviewMode() {                                                                  
2099         return mState == State.OVERVIEW;                                                                 
2100     }                                                                                                    
2101                                                                                                          
2102     public boolean enterOverviewMode() {                                                                 
2103         if (mTouchState != TOUCH_STATE_REST) {                                                           
2104             return false;                                                                                
2105         }                                                                                                
2106         enableOverviewMode(true, -1, true);                                                              
2107         return true;                                                                                     
2108     }                                                                                                    
2109                                                                                                          
2110     public void exitOverviewMode(boolean animated) {                                                     
2111         exitOverviewMode(-1, animated);                                                                  
2112     }                                                                                                    
2113                                                                                                          
2114     public void exitOverviewMode(int snapPage, boolean animated) {                                       
2115         enableOverviewMode(false, snapPage, animated);                                                   
2116     }                                                                                                    
2117                                                                                                          
2118     private void enableOverviewMode(boolean enable, int snapPage, boolean animated) {                    
2119         State finalState = Workspace.State.OVERVIEW;                                                     
2120         if (!enable) {                                                                                   
2121             finalState = Workspace.State.NORMAL;                                                         
2122         }                                                                                                
2123                                                                                                          
2124         Animator workspaceAnim = getChangeStateAnimation(finalState, animated, 0, snapPage);             
2125         if (workspaceAnim != null) {                                                                     
2126             onTransitionPrepare();                                                                       
2127             workspaceAnim.addListener(new AnimatorListenerAdapter() {                                    
2128                 @Override                                                                                
2129                 public void onAnimationEnd(Animator arg0) {                                              
2130                     onTransitionEnd();                                                                   
2131                 }                                                                                        
2132             });                                                                                          
2133             workspaceAnim.start();                                                                       
2134         }                                                                                                
2135     }                                                                                                    
2136                                                                                                          
2137     int getOverviewModeTranslationY() {                                                                  
2138         LauncherAppState app = LauncherAppState.getInstance();                                           
2139         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                    
2140         Rect overviewBar = grid.getOverviewModeButtonBarRect();                                          
2141                                                                                                          
2142         int availableHeight = getViewportHeight();                                                       
2143         int scaledHeight = (int) (mOverviewModeShrinkFactor * getNormalChildHeight());                   
2144         int offsetFromTopEdge = (availableHeight - scaledHeight) / 2;                                    
2145         int offsetToCenterInOverview = (availableHeight - mInsets.top - overviewBar.height()             
2146                 - scaledHeight) / 2;                                                                     
2147                                                                                                          
2148         return -offsetFromTopEdge + mInsets.top + offsetToCenterInOverview;                              
2149     }                                                                                                    
2150                                                                                                          
2151     boolean shouldVoiceButtonProxyBeVisible() {                                                          
2152         if (isOnOrMovingToCustomContent()) {                                                             
2153             return false;                                                                                
2154         }                                                                                                
2155         if (mState != State.NORMAL) {                                                                    
2156             return false;                                                                                
2157         }                                                                                                
2158         return true;                                                                                     
2159     }                                                                                                    
2160                                                                                                          
2161     public void updateInteractionForState() {                                                            
2162         if (mState != State.NORMAL) {                                                                    
2163             mLauncher.onInteractionBegin();                                                              
2164         } else {                                                                                         
2165             mLauncher.onInteractionEnd();                                                                
2166         }                                                                                                
2167     }                                                                                                    
2168                                                                                                          
2169     private void setState(State state) {                                                                 
2170         mState = state;                                                                                  
2171         updateInteractionForState();                                                                     
2172         updateAccessibilityFlags();                                                                      
2173     }                                                                                                    
2174                                                                                                          
2175     State getState() {                                                                                   
2176         return mState;                                                                                   
2177     }                                                                                                    
2178                                                                                                          
2179     private void updateAccessibilityFlags() {                                                            
2180         int accessible = mState == State.NORMAL ?                                                        
2181                 ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES :                                             
2182                 ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS;                              
2183         setImportantForAccessibility(accessible);                                                        
2184     }                                                                                                    
2185                                                                                                          
2186     private static final int HIDE_WORKSPACE_DURATION = 100;                                              
2187                                                                                                          
2188     Animator getChangeStateAnimation(final State state, boolean animated, int delay, int snapPage) {     
2189         return getChangeStateAnimation(state, animated, delay, snapPage, null);                          
2190     }                                                                                                    
2191                                                                                                          
2192     Animator getChangeStateAnimation(final State state, boolean animated, int delay, int snapPage,       
2193             ArrayList<View> layerViews) {                                                                
2194         if (mState == state) {                                                                           
2195             return null;                                                                                 
2196         }                                                                                                
2197                                                                                                          
2198         // Initialize animation arrays for the first time if necessary                                   
2199         initAnimationArrays();                                                                           
2200                                                                                                          
2201         AnimatorSet anim = animated ? LauncherAnimUtils.createAnimatorSet() : null;                      
2202                                                                                                          
2203         final State oldState = mState;                                                                   
2204         final boolean oldStateIsNormal = (oldState == State.NORMAL);                                     
2205         final boolean oldStateIsSpringLoaded = (oldState == State.SPRING_LOADED);                        
2206         final boolean oldStateIsNormalHidden = (oldState == State.NORMAL_HIDDEN);                        
2207         final boolean oldStateIsOverviewHidden = (oldState == State.OVERVIEW_HIDDEN);                    
2208         final boolean oldStateIsOverview = (oldState == State.OVERVIEW);                                 
2209         setState(state);                                                                                 
2210         final boolean stateIsNormal = (state == State.NORMAL);                                           
2211         final boolean stateIsSpringLoaded = (state == State.SPRING_LOADED);                              
2212         final boolean stateIsNormalHidden = (state == State.NORMAL_HIDDEN);                              
2213         final boolean stateIsOverviewHidden = (state == State.OVERVIEW_HIDDEN);                          
2214         final boolean stateIsOverview = (state == State.OVERVIEW);                                       
2215         float finalBackgroundAlpha = (stateIsSpringLoaded || stateIsOverview) ? 1.0f : 0f;               
2216         float finalHotseatAndPageIndicatorAlpha = (stateIsNormal || stateIsSpringLoaded) ? 1f : 0f;      
2217         float finalOverviewPanelAlpha = stateIsOverview ? 1f : 0f;                                       
2218         float finalSearchBarAlpha = !stateIsNormal ? 0f : 1f;                                            
2219         float finalWorkspaceTranslationY = stateIsOverview || stateIsOverviewHidden ?                    
2220                 getOverviewModeTranslationY() : 0;                                                       
2221                                                                                                          
2222         boolean workspaceToAllApps = (oldStateIsNormal && stateIsNormalHidden);                          
2223         boolean overviewToAllApps = (oldStateIsOverview && stateIsOverviewHidden);                       
2224         boolean allAppsToWorkspace = (stateIsNormalHidden && stateIsNormal);                             
2225         boolean workspaceToOverview = (oldStateIsNormal && stateIsOverview);                             
2226         boolean overviewToWorkspace = (oldStateIsOverview && stateIsNormal);                             
2227                                                                                                          
2228         mNewScale = 1.0f;                                                                                
2229                                                                                                          
2230         if (oldStateIsOverview) {                                                                        
2231             disableFreeScroll();                                                                         
2232         } else if (stateIsOverview) {                                                                    
2233             enableFreeScroll();                                                                          
2234         }                                                                                                
2235                                                                                                          
2236         if (state != State.NORMAL) {                                                                     
2237             if (stateIsSpringLoaded) {                                                                   
2238                 mNewScale = mSpringLoadedShrinkFactor;                                                   
2239             } else if (stateIsOverview || stateIsOverviewHidden) {                                       
2240                 mNewScale = mOverviewModeShrinkFactor;                                                   
2241             }                                                                                            
2242         }                                                                                                
2243                                                                                                          
2244         final int duration;                                                                              
2245         if (workspaceToAllApps || overviewToAllApps) {                                                   
2246             duration = HIDE_WORKSPACE_DURATION; //getResources().getInteger(R.integer.config_workspaceUns🔵
2247         } else if (workspaceToOverview || overviewToWorkspace) {                                         
2248             duration = getResources().getInteger(R.integer.config_overviewTransitionTime);               
2249         } else {                                                                                         
2250             duration = getResources().getInteger(R.integer.config_appsCustomizeWorkspaceShrinkTime);     
2251         }                                                                                                
2252                                                                                                          
2253         if (snapPage == -1) {                                                                            
2254             snapPage = getPageNearestToCenterOfScreen();                                                 
2255         }                                                                                                
2256         snapToPage(snapPage, duration, mZoomInInterpolator);                                             
2257                                                                                                          
2258         for (int i = 0; i < getChildCount(); i++) {                                                      
2259             final CellLayout cl = (CellLayout) getChildAt(i);                                            
2260             boolean isCurrentPage = (i == snapPage);                                                     
2261             float initialAlpha = cl.getShortcutsAndWidgets().getAlpha();                                 
2262             float finalAlpha;                                                                            
2263             if (stateIsNormalHidden || stateIsOverviewHidden) {                                          
2264                 finalAlpha = 0f;                                                                         
2265             } else if (stateIsNormal && mWorkspaceFadeInAdjacentScreens) {                               
2266                 finalAlpha = (i == snapPage || i < numCustomPages()) ? 1f : 0f;                          
2267             } else {                                                                                     
2268                 finalAlpha = 1f;                                                                         
2269             }                                                                                            
2270                                                                                                          
2271             // If we are animating to/from the small state, then hide the side pages and fade the        
2272             // current page in                                                                           
2273             if (!mIsSwitchingState) {                                                                    
2274                 if (workspaceToAllApps || allAppsToWorkspace) {                                          
2275                     if (allAppsToWorkspace && isCurrentPage) {                                           
2276                         initialAlpha = 0f;                                                               
2277                     } else if (!isCurrentPage) {                                                         
2278                         initialAlpha = finalAlpha = 0f;                                                  
2279                     }                                                                                    
2280                     cl.setShortcutAndWidgetAlpha(initialAlpha);                                          
2281                 }                                                                                        
2282             }                                                                                            
2283                                                                                                          
2284             mOldAlphas[i] = initialAlpha;                                                                
2285             mNewAlphas[i] = finalAlpha;                                                                  
2286             if (animated) {                                                                              
2287                 mOldBackgroundAlphas[i] = cl.getBackgroundAlpha();                                       
2288                 mNewBackgroundAlphas[i] = finalBackgroundAlpha;                                          
2289             } else {                                                                                     
2290                 cl.setBackgroundAlpha(finalBackgroundAlpha);                                             
2291                 cl.setShortcutAndWidgetAlpha(finalAlpha);                                                
2292             }                                                                                            
2293         }                                                                                                
2294                                                                                                          
2295         final View searchBar = mLauncher.getQsbBar();                                                    
2296         final View overviewPanel = mLauncher.getOverviewPanel();                                         
2297         final View hotseat = mLauncher.getHotseat();                                                     
2298         final View pageIndicator = getPageIndicator();                                                   
2299         if (animated) {                                                                                  
2300             LauncherViewPropertyAnimator scale = new LauncherViewPropertyAnimator(this);                 
2301             scale.scaleX(mNewScale)                                                                      
2302                 .scaleY(mNewScale)                                                                       
2303                 .translationY(finalWorkspaceTranslationY)                                                
2304                 .setDuration(duration)                                                                   
2305                 .setInterpolator(mZoomInInterpolator);                                                   
2306             anim.play(scale);                                                                            
2307             for (int index = 0; index < getChildCount(); index++) {                                      
2308                 final int i = index;                                                                     
2309                 final CellLayout cl = (CellLayout) getChildAt(i);                                        
2310                 float currentAlpha = cl.getShortcutsAndWidgets().getAlpha();                             
2311                 if (mOldAlphas[i] == 0 && mNewAlphas[i] == 0) {                                          
2312                     cl.setBackgroundAlpha(mNewBackgroundAlphas[i]);                                      
2313                     cl.setShortcutAndWidgetAlpha(mNewAlphas[i]);                                         
2314                 } else {                                                                                 
2315                     if (layerViews != null) {                                                            
2316                         layerViews.add(cl);                                                              
2317                     }                                                                                    
2318                     if (mOldAlphas[i] != mNewAlphas[i] || currentAlpha != mNewAlphas[i]) {               
2319                         LauncherViewPropertyAnimator alphaAnim =                                         
2320                             new LauncherViewPropertyAnimator(cl.getShortcutsAndWidgets());               
2321                         alphaAnim.alpha(mNewAlphas[i])                                                   
2322                             .setDuration(duration)                                                       
2323                             .setInterpolator(mZoomInInterpolator);                                       
2324                         anim.play(alphaAnim);                                                            
2325                     }                                                                                    
2326                     if (mOldBackgroundAlphas[i] != 0 ||                                                  
2327                         mNewBackgroundAlphas[i] != 0) {                                                  
2328                         ValueAnimator bgAnim =                                                           
2329                                 LauncherAnimUtils.ofFloat(cl, 0f, 1f);                                   
2330                         bgAnim.setInterpolator(mZoomInInterpolator);                                     
2331                         bgAnim.setDuration(duration);                                                    
2332                         bgAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {                  
2333                                 public void onAnimationUpdate(float a, float b) {                        
2334                                     cl.setBackgroundAlpha(                                               
2335                                             a * mOldBackgroundAlphas[i] +                                
2336                                             b * mNewBackgroundAlphas[i]);                                
2337                                 }                                                                        
2338                             });                                                                          
2339                         anim.play(bgAnim);                                                               
2340                     }                                                                                    
2341                 }                                                                                        
2342             }                                                                                            
2343             Animator pageIndicatorAlpha = null;                                                          
2344             if (pageIndicator != null) {                                                                 
2345                 pageIndicatorAlpha = new LauncherViewPropertyAnimator(pageIndicator)                     
2346                     .alpha(finalHotseatAndPageIndicatorAlpha).withLayer();                               
2347                 pageIndicatorAlpha.addListener(new AlphaUpdateListener(pageIndicator));                  
2348             } else {                                                                                     
2349                 // create a dummy animation so we don't need to do null checks later                     
2350                 pageIndicatorAlpha = ValueAnimator.ofFloat(0, 0);                                        
2351             }                                                                                            
2352                                                                                                          
2353             Animator hotseatAlpha = new LauncherViewPropertyAnimator(hotseat)                            
2354                 .alpha(finalHotseatAndPageIndicatorAlpha).withLayer();                                   
2355             hotseatAlpha.addListener(new AlphaUpdateListener(hotseat));                                  
2356                                                                                                          
2357             Animator searchBarAlpha = new LauncherViewPropertyAnimator(searchBar)                        
2358                 .alpha(finalSearchBarAlpha).withLayer();                                                 
2359             searchBarAlpha.addListener(new AlphaUpdateListener(searchBar));                              
2360                                                                                                          
2361             Animator overviewPanelAlpha = new LauncherViewPropertyAnimator(overviewPanel)                
2362                 .alpha(finalOverviewPanelAlpha).withLayer();                                             
2363             overviewPanelAlpha.addListener(new AlphaUpdateListener(overviewPanel));                      
2364                                                                                                          
2365             // For animation optimations, we may need to provide the Launcher transition                 
2366             // with a set of views on which to force build layers in certain scenarios.                  
2367             hotseat.setLayerType(View.LAYER_TYPE_HARDWARE, null);                                        
2368             searchBar.setLayerType(View.LAYER_TYPE_HARDWARE, null);                                      
2369             overviewPanel.setLayerType(View.LAYER_TYPE_HARDWARE, null);                                  
2370             if (layerViews != null) {                                                                    
2371                 layerViews.add(hotseat);                                                                 
2372                 layerViews.add(searchBar);                                                               
2373                 layerViews.add(overviewPanel);                                                           
2374             }                                                                                            
2375                                                                                                          
2376             if (workspaceToOverview) {                                                                   
2377                 pageIndicatorAlpha.setInterpolator(new DecelerateInterpolator(2));                       
2378                 hotseatAlpha.setInterpolator(new DecelerateInterpolator(2));                             
2379                 overviewPanelAlpha.setInterpolator(null);                                                
2380             } else if (overviewToWorkspace) {                                                            
2381                 pageIndicatorAlpha.setInterpolator(null);                                                
2382                 hotseatAlpha.setInterpolator(null);                                                      
2383                 overviewPanelAlpha.setInterpolator(new DecelerateInterpolator(2));                       
2384             }                                                                                            
2385                                                                                                          
2386             overviewPanelAlpha.setDuration(duration);                                                    
2387             pageIndicatorAlpha.setDuration(duration);                                                    
2388             hotseatAlpha.setDuration(duration);                                                          
2389             searchBarAlpha.setDuration(duration);                                                        
2390                                                                                                          
2391             anim.play(overviewPanelAlpha);                                                               
2392             anim.play(hotseatAlpha);                                                                     
2393             anim.play(searchBarAlpha);                                                                   
2394             anim.play(pageIndicatorAlpha);                                                               
2395             anim.setStartDelay(delay);                                                                   
2396         } else {                                                                                         
2397             overviewPanel.setAlpha(finalOverviewPanelAlpha);                                             
2398             AlphaUpdateListener.updateVisibility(overviewPanel);                                         
2399             hotseat.setAlpha(finalHotseatAndPageIndicatorAlpha);                                         
2400             AlphaUpdateListener.updateVisibility(hotseat);                                               
2401             if (pageIndicator != null) {                                                                 
2402                 pageIndicator.setAlpha(finalHotseatAndPageIndicatorAlpha);                               
2403                 AlphaUpdateListener.updateVisibility(pageIndicator);                                     
2404             }                                                                                            
2405             searchBar.setAlpha(finalSearchBarAlpha);                                                     
2406             AlphaUpdateListener.updateVisibility(searchBar);                                             
2407             updateCustomContentVisibility();                                                             
2408             setScaleX(mNewScale);                                                                        
2409             setScaleY(mNewScale);                                                                        
2410             setTranslationY(finalWorkspaceTranslationY);                                                 
2411         }                                                                                                
2412         mLauncher.updateVoiceButtonProxyVisible(false);                                                  
2413                                                                                                          
2414         if (stateIsNormal) {                                                                             
2415             animateBackgroundGradient(0f, animated);                                                     
2416         } else {                                                                                         
2417             animateBackgroundGradient(getResources().getInteger(                                         
2418                     R.integer.config_workspaceScrimAlpha) / 100f, animated);                             
2419         }                                                                                                
2420         return anim;                                                                                     
2421     }                                                                                                    
2422                                                                                                          
2423     static class AlphaUpdateListener implements AnimatorUpdateListener, AnimatorListener {               
2424         View view;                                                                                       
2425         public AlphaUpdateListener(View v) {                                                             
2426             view = v;                                                                                    
2427         }                                                                                                
2428                                                                                                          
2429         @Override                                                                                        
2430         public void onAnimationUpdate(ValueAnimator arg0) {                                              
2431             updateVisibility(view);                                                                      
2432         }                                                                                                
2433                                                                                                          
2434         public static void updateVisibility(View view) {                                                 
2435             // We want to avoid the extra layout pass by setting the views to GONE unless                
2436             // accessibility is on, in which case not setting them to GONE causes a glitch.              
2437             int invisibleState = sAccessibilityEnabled ? GONE : INVISIBLE;                               
2438             if (view.getAlpha() < ALPHA_CUTOFF_THRESHOLD && view.getVisibility() != invisibleState) {    
2439                 view.setVisibility(invisibleState);                                                      
2440             } else if (view.getAlpha() > ALPHA_CUTOFF_THRESHOLD                                          
2441                     && view.getVisibility() != VISIBLE) {                                                
2442                 view.setVisibility(VISIBLE);                                                             
2443             }                                                                                            
2444         }                                                                                                
2445                                                                                                          
2446         @Override                                                                                        
2447         public void onAnimationCancel(Animator arg0) {                                                   
2448         }                                                                                                
2449                                                                                                          
2450         @Override                                                                                        
2451         public void onAnimationEnd(Animator arg0) {                                                      
2452             updateVisibility(view);                                                                      
2453         }                                                                                                
2454                                                                                                          
2455         @Override                                                                                        
2456         public void onAnimationRepeat(Animator arg0) {                                                   
2457         }                                                                                                
2458                                                                                                          
2459         @Override                                                                                        
2460         public void onAnimationStart(Animator arg0) {                                                    
2461             // We want the views to be visible for animation, so fade-in/out is visible                  
2462             view.setVisibility(VISIBLE);                                                                 
2463         }                                                                                                
2464     }                                                                                                    
2465                                                                                                          
2466     @Override                                                                                            
2467     public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) {         
2468         onTransitionPrepare();                                                                           
2469     }                                                                                                    
2470                                                                                                          
2471     @Override                                                                                            
2472     public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) {           
2473     }                                                                                                    
2474                                                                                                          
2475     @Override                                                                                            
2476     public void onLauncherTransitionStep(Launcher l, float t) {                                          
2477         mTransitionProgress = t;                                                                         
2478     }                                                                                                    
2479                                                                                                          
2480     @Override                                                                                            
2481     public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {             
2482         onTransitionEnd();                                                                               
2483     }                                                                                                    
2484                                                                                                          
2485     private void onTransitionPrepare() {                                                                 
2486         mIsSwitchingState = true;                                                                        
2487                                                                                                          
2488         // Invalidate here to ensure that the pages are rendered during the state change transition.     
2489         invalidate();                                                                                    
2490                                                                                                          
2491         updateChildrenLayersEnabled(false);                                                              
2492         hideCustomContentIfNecessary();                                                                  
2493     }                                                                                                    
2494                                                                                                          
2495     void updateCustomContentVisibility() {                                                               
2496         int visibility = mState == Workspace.State.NORMAL ? VISIBLE : INVISIBLE;                         
2497         if (hasCustomContent()) {                                                                        
2498             mWorkspaceScreens.get(CUSTOM_CONTENT_SCREEN_ID).setVisibility(visibility);                   
2499         }                                                                                                
2500     }                                                                                                    
2501                                                                                                          
2502     void showCustomContentIfNecessary() {                                                                
2503         boolean show  = mState == Workspace.State.NORMAL;                                                
2504         if (show && hasCustomContent()) {                                                                
2505             mWorkspaceScreens.get(CUSTOM_CONTENT_SCREEN_ID).setVisibility(VISIBLE);                      
2506         }                                                                                                
2507     }                                                                                                    
2508                                                                                                          
2509     void hideCustomContentIfNecessary() {                                                                
2510         boolean hide  = mState != Workspace.State.NORMAL;                                                
2511         if (hide && hasCustomContent()) {                                                                
2512             disableLayoutTransitions();                                                                  
2513             mWorkspaceScreens.get(CUSTOM_CONTENT_SCREEN_ID).setVisibility(INVISIBLE);                    
2514             enableLayoutTransitions();                                                                   
2515         }                                                                                                
2516     }                                                                                                    
2517                                                                                                          
2518     private void onTransitionEnd() {                                                                     
2519         mIsSwitchingState = false;                                                                       
2520         updateChildrenLayersEnabled(false);                                                              
2521         showCustomContentIfNecessary();                                                                  
2522     }                                                                                                    
2523                                                                                                          
2524     @Override                                                                                            
2525     public View getContent() {                                                                           
2526         return this;                                                                                     
2527     }                                                                                                    
2528                                                                                                          
2529     /**                                                                                                  
2530      * Draw the View v into the given Canvas.                                                            
2531      *                                                                                                   
2532      * @param v the view to draw                                                                         
2533      * @param destCanvas the canvas to draw on                                                           
2534      * @param padding the horizontal and vertical padding to use when drawing                            
2535      */                                                                                                  
2536     private static void drawDragView(View v, Canvas destCanvas, int padding) {                           
2537         final Rect clipRect = sTempRect;                                                                 
2538         v.getDrawingRect(clipRect);                                                                      
2539                                                                                                          
2540         boolean textVisible = false;                                                                     
2541                                                                                                          
2542         destCanvas.save();                                                                               
2543         if (v instanceof TextView) {                                                                     
2544             Drawable d = ((TextView) v).getCompoundDrawables()[1];                                       
2545             Rect bounds = getDrawableBounds(d);                                                          
2546             clipRect.set(0, 0, bounds.width() + padding, bounds.height() + padding);                     
2547             destCanvas.translate(padding / 2 - bounds.left, padding / 2 - bounds.top);                   
2548             d.draw(destCanvas);                                                                          
2549         } else {                                                                                         
2550             if (v instanceof FolderIcon) {                                                               
2551                 // For FolderIcons the text can bleed into the icon area, and so we need to              
2552                 // hide the text completely (which can't be achieved by clipping).                       
2553                 if (((FolderIcon) v).getTextVisible()) {                                                 
2554                     ((FolderIcon) v).setTextVisible(false);                                              
2555                     textVisible = true;                                                                  
2556                 }                                                                                        
2557             }                                                                                            
2558             destCanvas.translate(-v.getScrollX() + padding / 2, -v.getScrollY() + padding / 2);          
2559             destCanvas.clipRect(clipRect, Op.REPLACE);                                                   
2560             v.draw(destCanvas);                                                                          
2561                                                                                                          
2562             // Restore text visibility of FolderIcon if necessary                                        
2563             if (textVisible) {                                                                           
2564                 ((FolderIcon) v).setTextVisible(true);                                                   
2565             }                                                                                            
2566         }                                                                                                
2567         destCanvas.restore();                                                                            
2568     }                                                                                                    
2569                                                                                                          
2570     /**                                                                                                  
2571      * Returns a new bitmap to show when the given View is being dragged around.                         
2572      * Responsibility for the bitmap is transferred to the caller.                                       
2573      * @param expectedPadding padding to add to the drag view. If a different padding was used           
2574      * its value will be changed                                                                         
2575      */                                                                                                  
2576     public Bitmap createDragBitmap(View v, AtomicInteger expectedPadding) {                              
2577         Bitmap b;                                                                                        
2578                                                                                                          
2579         int padding = expectedPadding.get();                                                             
2580         if (v instanceof TextView) {                                                                     
2581             Drawable d = ((TextView) v).getCompoundDrawables()[1];                                       
2582             Rect bounds = getDrawableBounds(d);                                                          
2583             b = Bitmap.createBitmap(bounds.width() + padding,                                            
2584                     bounds.height() + padding, Bitmap.Config.ARGB_8888);                                 
2585             expectedPadding.set(padding - bounds.left - bounds.top);                                     
2586         } else {                                                                                         
2587             b = Bitmap.createBitmap(                                                                     
2588                     v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);           
2589         }                                                                                                
2590                                                                                                          
2591         mCanvas.setBitmap(b);                                                                            
2592         drawDragView(v, mCanvas, padding);                                                               
2593         mCanvas.setBitmap(null);                                                                         
2594                                                                                                          
2595         return b;                                                                                        
2596     }                                                                                                    
2597                                                                                                          
2598     /**                                                                                                  
2599      * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.       
2600      * Responsibility for the bitmap is transferred to the caller.                                       
2601      */                                                                                                  
2602     private Bitmap createDragOutline(View v, int padding) {                                              
2603         final int outlineColor = getResources().getColor(R.color.outline_color);                         
2604         final Bitmap b = Bitmap.createBitmap(                                                            
2605                 v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);               
2606                                                                                                          
2607         mCanvas.setBitmap(b);                                                                            
2608         drawDragView(v, mCanvas, padding);                                                               
2609         mOutlineHelper.applyExpensiveOutlineWithBlur(b, mCanvas, outlineColor, outlineColor);            
2610         mCanvas.setBitmap(null);                                                                         
2611         return b;                                                                                        
2612     }                                                                                                    
2613                                                                                                          
2614     /**                                                                                                  
2615      * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.       
2616      * Responsibility for the bitmap is transferred to the caller.                                       
2617      */                                                                                                  
2618     private Bitmap createDragOutline(Bitmap orig, int padding, int w, int h,                             
2619             boolean clipAlpha) {                                                                         
2620         final int outlineColor = getResources().getColor(R.color.outline_color);                         
2621         final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);                             
2622         mCanvas.setBitmap(b);                                                                            
2623                                                                                                          
2624         Rect src = new Rect(0, 0, orig.getWidth(), orig.getHeight());                                    
2625         float scaleFactor = Math.min((w - padding) / (float) orig.getWidth(),                            
2626                 (h - padding) / (float) orig.getHeight());                                               
2627         int scaledWidth = (int) (scaleFactor * orig.getWidth());                                         
2628         int scaledHeight = (int) (scaleFactor * orig.getHeight());                                       
2629         Rect dst = new Rect(0, 0, scaledWidth, scaledHeight);                                            
2630                                                                                                          
2631         // center the image                                                                              
2632         dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2);                                       
2633                                                                                                          
2634         mCanvas.drawBitmap(orig, src, dst, null);                                                        
2635         mOutlineHelper.applyExpensiveOutlineWithBlur(b, mCanvas, outlineColor, outlineColor,             
2636                 clipAlpha);                                                                              
2637         mCanvas.setBitmap(null);                                                                         
2638                                                                                                          
2639         return b;                                                                                        
2640     }                                                                                                    
2641                                                                                                          
2642     void startDrag(CellLayout.CellInfo cellInfo) {                                                       
2643         View child = cellInfo.cell;                                                                      
2644                                                                                                          
2645         // Make sure the drag was started by a long press as opposed to a long click.                    
2646         if (!child.isInTouchMode()) {                                                                    
2647             return;                                                                                      
2648         }                                                                                                
2649                                                                                                          
2650         mDragInfo = cellInfo;                                                                            
2651         child.setVisibility(INVISIBLE);                                                                  
2652         CellLayout layout = (CellLayout) child.getParent().getParent();                                  
2653         layout.prepareChildForDrag(child);                                                               
2654                                                                                                          
2655         beginDragShared(child, this);                                                                    
2656     }                                                                                                    
2657                                                                                                          
2658     public void beginDragShared(View child, DragSource source) {                                         
2659         child.clearFocus();                                                                              
2660         child.setPressed(false);                                                                         
2661                                                                                                          
2662         // The outline is used to visualize where the item will land if dropped                          
2663         mDragOutline = createDragOutline(child, DRAG_BITMAP_PADDING);                                    
2664                                                                                                          
2665         mLauncher.onDragStarted(child);                                                                  
2666         // The drag bitmap follows the touch point around on the screen                                  
2667         AtomicInteger padding = new AtomicInteger(DRAG_BITMAP_PADDING);                                  
2668         final Bitmap b = createDragBitmap(child, padding);                                               
2669                                                                                                          
2670         final int bmpWidth = b.getWidth();                                                               
2671         final int bmpHeight = b.getHeight();                                                             
2672                                                                                                          
2673         float scale = mLauncher.getDragLayer().getLocationInDragLayer(child, mTempXY);                   
2674         int dragLayerX = Math.round(mTempXY[0] - (bmpWidth - scale * child.getWidth()) / 2);             
2675         int dragLayerY = Math.round(mTempXY[1] - (bmpHeight - scale * bmpHeight) / 2                     
2676                         - padding.get() / 2);                                                            
2677                                                                                                          
2678         LauncherAppState app = LauncherAppState.getInstance();                                           
2679         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                    
2680         Point dragVisualizeOffset = null;                                                                
2681         Rect dragRect = null;                                                                            
2682         if (child instanceof BubbleTextView) {                                                           
2683             int iconSize = grid.iconSizePx;                                                              
2684             int top = child.getPaddingTop();                                                             
2685             int left = (bmpWidth - iconSize) / 2;                                                        
2686             int right = left + iconSize;                                                                 
2687             int bottom = top + iconSize;                                                                 
2688             dragLayerY += top;                                                                           
2689             // Note: The drag region is used to calculate drag layer offsets, but the                    
2690             // dragVisualizeOffset in addition to the dragRect (the size) to position the outline.       
2691             dragVisualizeOffset = new Point(-padding.get() / 2, padding.get() / 2);                      
2692             dragRect = new Rect(left, top, right, bottom);                                               
2693         } else if (child instanceof FolderIcon) {                                                        
2694             int previewSize = grid.folderIconSizePx;                                                     
2695             dragRect = new Rect(0, child.getPaddingTop(), child.getWidth(), previewSize);                
2696         }                                                                                                
2697                                                                                                          
2698         // Clear the pressed state if necessary                                                          
2699         if (child instanceof BubbleTextView) {                                                           
2700             BubbleTextView icon = (BubbleTextView) child;                                                
2701             icon.clearPressedBackground();                                                               
2702         }                                                                                                
2703                                                                                                          
2704         if (child.getTag() == null || !(child.getTag() instanceof ItemInfo)) {                           
2705             String msg = "Drag started with a view that has no tag set. This "                           
2706                     + "will cause a crash (issue 11627249) down the line. "                              
2707                     + "View: " + child + "  tag: " + child.getTag();                                     
2708             throw new IllegalStateException(msg);                                                        
2709         }                                                                                                
2710                                                                                                          
2711         DragView dv = mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(),       
2712                 DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, scale);                  
2713         dv.setIntrinsicIconScaleFactor(source.getIntrinsicIconScaleFactor());                            
2714                                                                                                          
2715         if (child.getParent() instanceof ShortcutAndWidgetContainer) {                                   
2716             mDragSourceInternal = (ShortcutAndWidgetContainer) child.getParent();                        
2717         }                                                                                                
2718                                                                                                          
2719         b.recycle();                                                                                     
2720     }                                                                                                    
2721                                                                                                          
2722     public void beginExternalDragShared(View child, DragSource source) {                                 
2723         LauncherAppState app = LauncherAppState.getInstance();                                           
2724         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                    
2725         int iconSize = grid.iconSizePx;                                                                  
2726                                                                                                          
2727         // Notify launcher of drag start                                                                 
2728         mLauncher.onDragStarted(child);                                                                  
2729                                                                                                          
2730         // Compose a new drag bitmap that is of the icon size                                            
2731         AtomicInteger padding = new AtomicInteger(DRAG_BITMAP_PADDING);                                  
2732         final Bitmap tmpB = createDragBitmap(child, padding);                                            
2733         Bitmap b = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);                     
2734         Paint p = new Paint();                                                                           
2735         p.setFilterBitmap(true);                                                                         
2736         mCanvas.setBitmap(b);                                                                            
2737         mCanvas.drawBitmap(tmpB, new Rect(0, 0, tmpB.getWidth(), tmpB.getHeight()),                      
2738                 new Rect(0, 0, iconSize, iconSize), p);                                                  
2739         mCanvas.setBitmap(null);                                                                         
2740                                                                                                          
2741         // Find the child's location on the screen                                                       
2742         int bmpWidth = tmpB.getWidth();                                                                  
2743         float iconScale = (float) bmpWidth / iconSize;                                                   
2744         float scale = mLauncher.getDragLayer().getLocationInDragLayer(child, mTempXY) * iconScale;       
2745         int dragLayerX = Math.round(mTempXY[0] - (bmpWidth - scale * child.getWidth()) / 2);             
2746         int dragLayerY = Math.round(mTempXY[1]);                                                         
2747                                                                                                          
2748         // Note: The drag region is used to calculate drag layer offsets, but the                        
2749         // dragVisualizeOffset in addition to the dragRect (the size) to position the outline.           
2750         Point dragVisualizeOffset = new Point(-padding.get() / 2, padding.get() / 2);                    
2751         Rect dragRect = new Rect(0, 0, iconSize, iconSize);                                              
2752                                                                                                          
2753         if (child.getTag() == null || !(child.getTag() instanceof ItemInfo)) {                           
2754             String msg = "Drag started with a view that has no tag set. This "                           
2755                     + "will cause a crash (issue 11627249) down the line. "                              
2756                     + "View: " + child + "  tag: " + child.getTag();                                     
2757             throw new IllegalStateException(msg);                                                        
2758         }                                                                                                
2759                                                                                                          
2760         // Start the drag                                                                                
2761         DragView dv = mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(),       
2762                 DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, scale);                  
2763         dv.setIntrinsicIconScaleFactor(source.getIntrinsicIconScaleFactor());                            
2764                                                                                                          
2765         // Recycle temporary bitmaps                                                                     
2766         tmpB.recycle();                                                                                  
2767     }                                                                                                    
2768                                                                                                          
2769     void addApplicationShortcut(ShortcutInfo info, CellLayout target, long container, long screenId,     
2770             int cellX, int cellY, boolean insertAtFirst, int intersectX, int intersectY) {               
2771         View view = mLauncher.createShortcut(R.layout.application, target, (ShortcutInfo) info);         
2772                                                                                                          
2773         final int[] cellXY = new int[2];                                                                 
2774         target.findCellForSpanThatIntersects(cellXY, 1, 1, intersectX, intersectY);                      
2775         addInScreen(view, container, screenId, cellXY[0], cellXY[1], 1, 1, insertAtFirst);               
2776                                                                                                          
2777         LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screenId, cellXY[0],           
2778                 cellXY[1]);                                                                              
2779     }                                                                                                    
2780                                                                                                          
2781     public boolean transitionStateShouldAllowDrop() {                                                    
2782         return ((!isSwitchingState() || mTransitionProgress > 0.5f) &&                                   
2783                 (mState == State.NORMAL || mState == State.SPRING_LOADED));                              
2784     }                                                                                                    
2785                                                                                                          
2786     /**                                                                                                  
2787      * {@inheritDoc}                                                                                     
2788      */                                                                                                  
2789     public boolean acceptDrop(DragObject d) {                                                            
2790         // If it's an external drop (e.g. from All Apps), check if it should be accepted                 
2791         CellLayout dropTargetLayout = mDropToLayout;                                                     
2792         if (d.dragSource != this) {                                                                      
2793             // Don't accept the drop if we're not over a screen at time of drop                          
2794             if (dropTargetLayout == null) {                                                              
2795                 return false;                                                                            
2796             }                                                                                            
2797             if (!transitionStateShouldAllowDrop()) return false;                                         
2798                                                                                                          
2799             mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset,              
2800                     d.dragView, mDragViewVisualCenter);                                                  
2801                                                                                                          
2802             // We want the point to be mapped to the dragTarget.                                         
2803             if (mLauncher.isHotseatLayout(dropTargetLayout)) {                                           
2804                 mapPointFromSelfToHotseatLayout(mLauncher.getHotseat(), mDragViewVisualCenter);          
2805             } else {                                                                                     
2806                 mapPointFromSelfToChild(dropTargetLayout, mDragViewVisualCenter, null);                  
2807             }                                                                                            
2808                                                                                                          
2809             int spanX = 1;                                                                               
2810             int spanY = 1;                                                                               
2811             if (mDragInfo != null) {                                                                     
2812                 final CellLayout.CellInfo dragCellInfo = mDragInfo;                                      
2813                 spanX = dragCellInfo.spanX;                                                              
2814                 spanY = dragCellInfo.spanY;                                                              
2815             } else {                                                                                     
2816                 final ItemInfo dragInfo = (ItemInfo) d.dragInfo;                                         
2817                 spanX = dragInfo.spanX;                                                                  
2818                 spanY = dragInfo.spanY;                                                                  
2819             }                                                                                            
2820                                                                                                          
2821             int minSpanX = spanX;                                                                        
2822             int minSpanY = spanY;                                                                        
2823             if (d.dragInfo instanceof PendingAddWidgetInfo) {                                            
2824                 minSpanX = ((PendingAddWidgetInfo) d.dragInfo).minSpanX;                                 
2825                 minSpanY = ((PendingAddWidgetInfo) d.dragInfo).minSpanY;                                 
2826             }                                                                                            
2827                                                                                                          
2828             mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],                                
2829                     (int) mDragViewVisualCenter[1], minSpanX, minSpanY, dropTargetLayout,                
2830                     mTargetCell);                                                                        
2831             float distance = dropTargetLayout.getDistanceFromCell(mDragViewVisualCenter[0],              
2832                     mDragViewVisualCenter[1], mTargetCell);                                              
2833             if (mCreateUserFolderOnDrop && willCreateUserFolder((ItemInfo) d.dragInfo,                   
2834                     dropTargetLayout, mTargetCell, distance, true)) {                                    
2835                 return true;                                                                             
2836             }                                                                                            
2837                                                                                                          
2838             if (mAddToExistingFolderOnDrop && willAddToExistingUserFolder((ItemInfo) d.dragInfo,         
2839                     dropTargetLayout, mTargetCell, distance)) {                                          
2840                 return true;                                                                             
2841             }                                                                                            
2842                                                                                                          
2843             int[] resultSpan = new int[2];                                                               
2844             mTargetCell = dropTargetLayout.performReorder((int) mDragViewVisualCenter[0],                
2845                     (int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY,                    
2846                     null, mTargetCell, resultSpan, CellLayout.MODE_ACCEPT_DROP);                         
2847             boolean foundCell = mTargetCell[0] >= 0 && mTargetCell[1] >= 0;                              
2848                                                                                                          
2849             // Don't accept the drop if there's no room for the item                                     
2850             if (!foundCell) {                                                                            
2851                 // Don't show the message if we are dropping on the AllApps button and the hotseat       
2852                 // is full                                                                               
2853                 boolean isHotseat = mLauncher.isHotseatLayout(dropTargetLayout);                         
2854                 if (mTargetCell != null && isHotseat) {                                                  
2855                     Hotseat hotseat = mLauncher.getHotseat();                                            
2856                     if (hotseat.isAllAppsButtonRank(                                                     
2857                             hotseat.getOrderInHotseat(mTargetCell[0], mTargetCell[1]))) {                
2858                         return false;                                                                    
2859                     }                                                                                    
2860                 }                                                                                        
2861                                                                                                          
2862                 mLauncher.showOutOfSpaceMessage(isHotseat);                                              
2863                 return false;                                                                            
2864             }                                                                                            
2865         }                                                                                                
2866                                                                                                          
2867         long screenId = getIdForScreen(dropTargetLayout);                                                
2868         if (screenId == EXTRA_EMPTY_SCREEN_ID) {                                                         
2869             commitExtraEmptyScreen();                                                                    
2870         }                                                                                                
2871                                                                                                          
2872         return true;                                                                                     
2873     }                                                                                                    
2874                                                                                                          
2875     boolean willCreateUserFolder(ItemInfo info, CellLayout target, int[] targetCell, float               
2876             distance, boolean considerTimeout) {                                                         
2877         if (distance > mMaxDistanceForFolderCreation) return false;                                      
2878         View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);                             
2879                                                                                                          
2880         if (dropOverView != null) {                                                                      
2881             CellLayout.LayoutParams lp = (CellLayout.LayoutParams) dropOverView.getLayoutParams();       
2882             if (lp.useTmpCoords && (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.tmpCellY)) {            
2883                 return false;                                                                            
2884             }                                                                                            
2885         }                                                                                                
2886                                                                                                          
2887         boolean hasntMoved = false;                                                                      
2888         if (mDragInfo != null) {                                                                         
2889             hasntMoved = dropOverView == mDragInfo.cell;                                                 
2890         }                                                                                                
2891                                                                                                          
2892         if (dropOverView == null || hasntMoved || (considerTimeout && !mCreateUserFolderOnDrop)) {       
2893             return false;                                                                                
2894         }                                                                                                
2895                                                                                                          
2896         boolean aboveShortcut = (dropOverView.getTag() instanceof ShortcutInfo);                         
2897         boolean willBecomeShortcut =                                                                     
2898                 (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||                    
2899                 info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT);                         
2900                                                                                                          
2901         return (aboveShortcut && willBecomeShortcut);                                                    
2902     }                                                                                                    
2903                                                                                                          
2904     boolean willAddToExistingUserFolder(Object dragInfo, CellLayout target, int[] targetCell,            
2905             float distance) {                                                                            
2906         if (distance > mMaxDistanceForFolderCreation) return false;                                      
2907         View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);                             
2908                                                                                                          
2909         if (dropOverView != null) {                                                                      
2910             CellLayout.LayoutParams lp = (CellLayout.LayoutParams) dropOverView.getLayoutParams();       
2911             if (lp.useTmpCoords && (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.tmpCellY)) {            
2912                 return false;                                                                            
2913             }                                                                                            
2914         }                                                                                                
2915                                                                                                          
2916         if (dropOverView instanceof FolderIcon) {                                                        
2917             FolderIcon fi = (FolderIcon) dropOverView;                                                   
2918             if (fi.acceptDrop(dragInfo)) {                                                               
2919                 return true;                                                                             
2920             }                                                                                            
2921         }                                                                                                
2922         return false;                                                                                    
2923     }                                                                                                    
2924                                                                                                          
2925     boolean createUserFolderIfNecessary(View newView, long container, CellLayout target,                 
2926             int[] targetCell, float distance, boolean external, DragView dragView,                       
2927             Runnable postAnimationRunnable) {                                                            
2928         if (distance > mMaxDistanceForFolderCreation) return false;                                      
2929         View v = target.getChildAt(targetCell[0], targetCell[1]);                                        
2930                                                                                                          
2931         boolean hasntMoved = false;                                                                      
2932         if (mDragInfo != null) {                                                                         
2933             CellLayout cellParent = getParentCellLayoutForView(mDragInfo.cell);                          
2934             hasntMoved = (mDragInfo.cellX == targetCell[0] &&                                            
2935                     mDragInfo.cellY == targetCell[1]) && (cellParent == target);                         
2936         }                                                                                                
2937                                                                                                          
2938         if (v == null || hasntMoved || !mCreateUserFolderOnDrop) return false;                           
2939         mCreateUserFolderOnDrop = false;                                                                 
2940         final long screenId = (targetCell == null) ? mDragInfo.screenId : getIdForScreen(target);        
2941                                                                                                          
2942         boolean aboveShortcut = (v.getTag() instanceof ShortcutInfo);                                    
2943         boolean willBecomeShortcut = (newView.getTag() instanceof ShortcutInfo);                         
2944                                                                                                          
2945         if (aboveShortcut && willBecomeShortcut) {                                                       
2946             ShortcutInfo sourceInfo = (ShortcutInfo) newView.getTag();                                   
2947             ShortcutInfo destInfo = (ShortcutInfo) v.getTag();                                           
2948             // if the drag started here, we need to remove it from the workspace                         
2949             if (!external) {                                                                             
2950                 getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell);                   
2951             }                                                                                            
2952                                                                                                          
2953             Rect folderLocation = new Rect();                                                            
2954             float scale = mLauncher.getDragLayer().getDescendantRectRelativeToSelf(v, folderLocation);   
2955             target.removeView(v);                                                                        
2956                                                                                                          
2957             FolderIcon fi =                                                                              
2958                 mLauncher.addFolder(target, container, screenId, targetCell[0], targetCell[1]);          
2959             destInfo.cellX = -1;                                                                         
2960             destInfo.cellY = -1;                                                                         
2961             sourceInfo.cellX = -1;                                                                       
2962             sourceInfo.cellY = -1;                                                                       
2963                                                                                                          
2964             // If the dragView is null, we can't animate                                                 
2965             boolean animate = dragView != null;                                                          
2966             if (animate) {                                                                               
2967                 fi.performCreateAnimation(destInfo, v, sourceInfo, dragView, folderLocation, scale,      
2968                         postAnimationRunnable);                                                          
2969             } else {                                                                                     
2970                 fi.addItem(destInfo);                                                                    
2971                 fi.addItem(sourceInfo);                                                                  
2972             }                                                                                            
2973             return true;                                                                                 
2974         }                                                                                                
2975         return false;                                                                                    
2976     }                                                                                                    
2977                                                                                                          
2978     boolean addToExistingFolderIfNecessary(View newView, CellLayout target, int[] targetCell,            
2979             float distance, DragObject d, boolean external) {                                            
2980         if (distance > mMaxDistanceForFolderCreation) return false;                                      
2981                                                                                                          
2982         View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);                             
2983         if (!mAddToExistingFolderOnDrop) return false;                                                   
2984         mAddToExistingFolderOnDrop = false;                                                              
2985                                                                                                          
2986         if (dropOverView instanceof FolderIcon) {                                                        
2987             FolderIcon fi = (FolderIcon) dropOverView;                                                   
2988             if (fi.acceptDrop(d.dragInfo)) {                                                             
2989                 fi.onDrop(d);                                                                            
2990                                                                                                          
2991                 // if the drag started here, we need to remove it from the workspace                     
2992                 if (!external) {                                                                         
2993                     getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell);               
2994                 }                                                                                        
2995                 return true;                                                                             
2996             }                                                                                            
2997         }                                                                                                
2998         return false;                                                                                    
2999     }                                                                                                    
3000                                                                                                          
3001     public void onDrop(final DragObject d) {                                                             
3002         mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, d.dragView,      
3003                 mDragViewVisualCenter);                                                                  
3004                                                                                                          
3005         CellLayout dropTargetLayout = mDropToLayout;                                                     
3006                                                                                                          
3007         // We want the point to be mapped to the dragTarget.                                             
3008         if (dropTargetLayout != null) {                                                                  
3009             if (mLauncher.isHotseatLayout(dropTargetLayout)) {                                           
3010                 mapPointFromSelfToHotseatLayout(mLauncher.getHotseat(), mDragViewVisualCenter);          
3011             } else {                                                                                     
3012                 mapPointFromSelfToChild(dropTargetLayout, mDragViewVisualCenter, null);                  
3013             }                                                                                            
3014         }                                                                                                
3015                                                                                                          
3016         int snapScreen = -1;                                                                             
3017         boolean resizeOnDrop = false;                                                                    
3018         if (d.dragSource != this) {                                                                      
3019             final int[] touchXY = new int[] { (int) mDragViewVisualCenter[0],                            
3020                     (int) mDragViewVisualCenter[1] };                                                    
3021             onDropExternal(touchXY, d.dragInfo, dropTargetLayout, false, d);                             
3022         } else if (mDragInfo != null) {                                                                  
3023             final View cell = mDragInfo.cell;                                                            
3024                                                                                                          
3025             Runnable resizeRunnable = null;                                                              
3026             if (dropTargetLayout != null && !d.cancelled) {                                              
3027                 // Move internally                                                                       
3028                 boolean hasMovedLayouts = (getParentCellLayoutForView(cell) != dropTargetLayout);        
3029                 boolean hasMovedIntoHotseat = mLauncher.isHotseatLayout(dropTargetLayout);               
3030                 long container = hasMovedIntoHotseat ?                                                   
3031                         LauncherSettings.Favorites.CONTAINER_HOTSEAT :                                   
3032                         LauncherSettings.Favorites.CONTAINER_DESKTOP;                                    
3033                 long screenId = (mTargetCell[0] < 0) ?                                                   
3034                         mDragInfo.screenId : getIdForScreen(dropTargetLayout);                           
3035                 int spanX = mDragInfo != null ? mDragInfo.spanX : 1;                                     
3036                 int spanY = mDragInfo != null ? mDragInfo.spanY : 1;                                     
3037                 // First we find the cell nearest to point at which the item is                          
3038                 // dropped, without any consideration to whether there is an item there.                 
3039                                                                                                          
3040                 mTargetCell = findNearestArea((int) mDragViewVisualCenter[0], (int)                      
3041                         mDragViewVisualCenter[1], spanX, spanY, dropTargetLayout, mTargetCell);          
3042                 float distance = dropTargetLayout.getDistanceFromCell(mDragViewVisualCenter[0],          
3043                         mDragViewVisualCenter[1], mTargetCell);                                          
3044                                                                                                          
3045                 // If the item being dropped is a shortcut and the nearest drop                          
3046                 // cell also contains a shortcut, then create a folder with the two shortcuts.           
3047                 if (!mInScrollArea && createUserFolderIfNecessary(cell, container,                       
3048                         dropTargetLayout, mTargetCell, distance, false, d.dragView, null)) {             
3049                     return;                                                                              
3050                 }                                                                                        
3051                                                                                                          
3052                 if (addToExistingFolderIfNecessary(cell, dropTargetLayout, mTargetCell,                  
3053                         distance, d, false)) {                                                           
3054                     return;                                                                              
3055                 }                                                                                        
3056                                                                                                          
3057                 // Aside from the special case where we're dropping a shortcut onto a shortcut,          
3058                 // we need to find the nearest cell location that is vacant                              
3059                 ItemInfo item = (ItemInfo) d.dragInfo;                                                   
3060                 int minSpanX = item.spanX;                                                               
3061                 int minSpanY = item.spanY;                                                               
3062                 if (item.minSpanX > 0 && item.minSpanY > 0) {                                            
3063                     minSpanX = item.minSpanX;                                                            
3064                     minSpanY = item.minSpanY;                                                            
3065                 }                                                                                        
3066                                                                                                          
3067                 int[] resultSpan = new int[2];                                                           
3068                 mTargetCell = dropTargetLayout.performReorder((int) mDragViewVisualCenter[0],            
3069                         (int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY, cell,          
3070                         mTargetCell, resultSpan, CellLayout.MODE_ON_DROP);                               
3071                                                                                                          
3072                 boolean foundCell = mTargetCell[0] >= 0 && mTargetCell[1] >= 0;                          
3073                                                                                                          
3074                 // if the widget resizes on drop                                                         
3075                 if (foundCell && (cell instanceof AppWidgetHostView) &&                                  
3076                         (resultSpan[0] != item.spanX || resultSpan[1] != item.spanY)) {                  
3077                     resizeOnDrop = true;                                                                 
3078                     item.spanX = resultSpan[0];                                                          
3079                     item.spanY = resultSpan[1];                                                          
3080                     AppWidgetHostView awhv = (AppWidgetHostView) cell;                                   
3081                     AppWidgetResizeFrame.updateWidgetSizeRanges(awhv, mLauncher, resultSpan[0],          
3082                             resultSpan[1]);                                                              
3083                 }                                                                                        
3084                                                                                                          
3085                 if (getScreenIdForPageIndex(mCurrentPage) != screenId && !hasMovedIntoHotseat) {         
3086                     snapScreen = getPageIndexForScreenId(screenId);                                      
3087                     snapToPage(snapScreen);                                                              
3088                 }                                                                                        
3089                                                                                                          
3090                 if (foundCell) {                                                                         
3091                     final ItemInfo info = (ItemInfo) cell.getTag();                                      
3092                     if (hasMovedLayouts) {                                                               
3093                         // Reparent the view                                                             
3094                         CellLayout parentCell = getParentCellLayoutForView(cell);                        
3095                         if (parentCell != null) {                                                        
3096                             parentCell.removeView(cell);                                                 
3097                         } else if (LauncherAppState.isDogfoodBuild()) {                                  
3098                             throw new NullPointerException("mDragInfo.cell has null parent");            
3099                         }                                                                                
3100                         addInScreen(cell, container, screenId, mTargetCell[0], mTargetCell[1],           
3101                                 info.spanX, info.spanY);                                                 
3102                     }                                                                                    
3103                                                                                                          
3104                     // update the item's position after drop                                             
3105                     CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();       
3106                     lp.cellX = lp.tmpCellX = mTargetCell[0];                                             
3107                     lp.cellY = lp.tmpCellY = mTargetCell[1];                                             
3108                     lp.cellHSpan = item.spanX;                                                           
3109                     lp.cellVSpan = item.spanY;                                                           
3110                     lp.isLockedToGrid = true;                                                            
3111                                                                                                          
3112                     if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT &&                     
3113                             cell instanceof LauncherAppWidgetHostView) {                                 
3114                         final CellLayout cellLayout = dropTargetLayout;                                  
3115                         // We post this call so that the widget has a chance to be placed                
3116                         // in its final location                                                         
3117                                                                                                          
3118                         final LauncherAppWidgetHostView hostView = (LauncherAppWidgetHostView) cell;     
3119                         AppWidgetProviderInfo pinfo = hostView.getAppWidgetInfo();                       
3120                         if (pinfo != null &&                                                             
3121                                 pinfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE) {                 
3122                             final Runnable addResizeFrame = new Runnable() {                             
3123                                 public void run() {                                                      
3124                                     DragLayer dragLayer = mLauncher.getDragLayer();                      
3125                                     dragLayer.addResizeFrame(info, hostView, cellLayout);                
3126                                 }                                                                        
3127                             };                                                                           
3128                             resizeRunnable = (new Runnable() {                                           
3129                                 public void run() {                                                      
3130                                     if (!isPageMoving()) {                                               
3131                                         addResizeFrame.run();                                            
3132                                     } else {                                                             
3133                                         mDelayedResizeRunnable = addResizeFrame;                         
3134                                     }                                                                    
3135                                 }                                                                        
3136                             });                                                                          
3137                         }                                                                                
3138                     }                                                                                    
3139                                                                                                          
3140                     LauncherModel.modifyItemInDatabase(mLauncher, info, container, screenId, lp.cellX,   
3141                             lp.cellY, item.spanX, item.spanY);                                           
3142                 } else {                                                                                 
3143                     // If we can't find a drop location, we return the item to its original position     
3144                     CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();       
3145                     mTargetCell[0] = lp.cellX;                                                           
3146                     mTargetCell[1] = lp.cellY;                                                           
3147                     CellLayout layout = (CellLayout) cell.getParent().getParent();                       
3148                     layout.markCellsAsOccupiedForView(cell);                                             
3149                 }                                                                                        
3150             }                                                                                            
3151                                                                                                          
3152             final CellLayout parent = (CellLayout) cell.getParent().getParent();                         
3153             final Runnable finalResizeRunnable = resizeRunnable;                                         
3154             // Prepare it to be animated into its new position                                           
3155             // This must be called after the view has been re-parented                                   
3156             final Runnable onCompleteRunnable = new Runnable() {                                         
3157                 @Override                                                                                
3158                 public void run() {                                                                      
3159                     mAnimatingViewIntoPlace = false;                                                     
3160                     updateChildrenLayersEnabled(false);                                                  
3161                     if (finalResizeRunnable != null) {                                                   
3162                         finalResizeRunnable.run();                                                       
3163                     }                                                                                    
3164                 }                                                                                        
3165             };                                                                                           
3166             mAnimatingViewIntoPlace = true;                                                              
3167             if (d.dragView.hasDrawn()) {                                                                 
3168                 final ItemInfo info = (ItemInfo) cell.getTag();                                          
3169                 if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET) {                   
3170                     int animationType = resizeOnDrop ? ANIMATE_INTO_POSITION_AND_RESIZE :                
3171                             ANIMATE_INTO_POSITION_AND_DISAPPEAR;                                         
3172                     animateWidgetDrop(info, parent, d.dragView,                                          
3173                             onCompleteRunnable, animationType, cell, false);                             
3174                 } else {                                                                                 
3175                     int duration = snapScreen < 0 ? -1 : ADJACENT_SCREEN_DROP_DURATION;                  
3176                     mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, cell, duration,         
3177                             onCompleteRunnable, this);                                                   
3178                 }                                                                                        
3179             } else {                                                                                     
3180                 d.deferDragViewCleanupPostAnimation = false;                                             
3181                 cell.setVisibility(VISIBLE);                                                             
3182             }                                                                                            
3183             parent.onDropChild(cell);                                                                    
3184         }                                                                                                
3185     }                                                                                                    
3186                                                                                                          
3187     public void setFinalScrollForPageChange(int pageIndex) {                                             
3188         CellLayout cl = (CellLayout) getChildAt(pageIndex);                                              
3189         if (cl != null) {                                                                                
3190             mSavedScrollX = getScrollX();                                                                
3191             mSavedTranslationX = cl.getTranslationX();                                                   
3192             mSavedRotationY = cl.getRotationY();                                                         
3193             final int newX = getScrollForPage(pageIndex);                                                
3194             setScrollX(newX);                                                                            
3195             cl.setTranslationX(0f);                                                                      
3196             cl.setRotationY(0f);                                                                         
3197         }                                                                                                
3198     }                                                                                                    
3199                                                                                                          
3200     public void resetFinalScrollForPageChange(int pageIndex) {                                           
3201         if (pageIndex >= 0) {                                                                            
3202             CellLayout cl = (CellLayout) getChildAt(pageIndex);                                          
3203             setScrollX(mSavedScrollX);                                                                   
3204             cl.setTranslationX(mSavedTranslationX);                                                      
3205             cl.setRotationY(mSavedRotationY);                                                            
3206         }                                                                                                
3207     }                                                                                                    
3208                                                                                                          
3209     public void getViewLocationRelativeToSelf(View v, int[] location) {                                  
3210         getLocationInWindow(location);                                                                   
3211         int x = location[0];                                                                             
3212         int y = location[1];                                                                             
3213                                                                                                          
3214         v.getLocationInWindow(location);                                                                 
3215         int vX = location[0];                                                                            
3216         int vY = location[1];                                                                            
3217                                                                                                          
3218         location[0] = vX - x;                                                                            
3219         location[1] = vY - y;                                                                            
3220     }                                                                                                    
3221                                                                                                          
3222     public void onDragEnter(DragObject d) {                                                              
3223         mDragEnforcer.onDragEnter();                                                                     
3224         mCreateUserFolderOnDrop = false;                                                                 
3225         mAddToExistingFolderOnDrop = false;                                                              
3226                                                                                                          
3227         mDropToLayout = null;                                                                            
3228         CellLayout layout = getCurrentDropLayout();                                                      
3229         setCurrentDropLayout(layout);                                                                    
3230         setCurrentDragOverlappingLayout(layout);                                                         
3231                                                                                                          
3232         if (!workspaceInModalState()) {                                                                  
3233             mLauncher.getDragLayer().showPageHints();                                                    
3234         }                                                                                                
3235     }                                                                                                    
3236                                                                                                          
3237     /** Return a rect that has the cellWidth/cellHeight (left, top), and                                 
3238      * widthGap/heightGap (right, bottom) */                                                             
3239     static Rect getCellLayoutMetrics(Launcher launcher, int orientation) {                               
3240         LauncherAppState app = LauncherAppState.getInstance();                                           
3241         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                    
3242                                                                                                          
3243         Display display = launcher.getWindowManager().getDefaultDisplay();                               
3244         Point smallestSize = new Point();                                                                
3245         Point largestSize = new Point();                                                                 
3246         display.getCurrentSizeRange(smallestSize, largestSize);                                          
3247         int countX = (int) grid.numColumns;                                                              
3248         int countY = (int) grid.numRows;                                                                 
3249         if (orientation == CellLayout.LANDSCAPE) {                                                       
3250             if (mLandscapeCellLayoutMetrics == null) {                                                   
3251                 Rect padding = grid.getWorkspacePadding(CellLayout.LANDSCAPE);                           
3252                 int width = largestSize.x - padding.left - padding.right;                                
3253                 int height = smallestSize.y - padding.top - padding.bottom;                              
3254                 mLandscapeCellLayoutMetrics = new Rect();                                                
3255                 mLandscapeCellLayoutMetrics.set(                                                         
3256                         grid.calculateCellWidth(width, countX),                                          
3257                         grid.calculateCellHeight(height, countY), 0, 0);                                 
3258             }                                                                                            
3259             return mLandscapeCellLayoutMetrics;                                                          
3260         } else if (orientation == CellLayout.PORTRAIT) {                                                 
3261             if (mPortraitCellLayoutMetrics == null) {                                                    
3262                 Rect padding = grid.getWorkspacePadding(CellLayout.PORTRAIT);                            
3263                 int width = smallestSize.x - padding.left - padding.right;                               
3264                 int height = largestSize.y - padding.top - padding.bottom;                               
3265                 mPortraitCellLayoutMetrics = new Rect();                                                 
3266                 mPortraitCellLayoutMetrics.set(                                                          
3267                         grid.calculateCellWidth(width, countX),                                          
3268                         grid.calculateCellHeight(height, countY), 0, 0);                                 
3269             }                                                                                            
3270             return mPortraitCellLayoutMetrics;                                                           
3271         }                                                                                                
3272         return null;                                                                                     
3273     }                                                                                                    
3274                                                                                                          
3275     public void onDragExit(DragObject d) {                                                               
3276         mDragEnforcer.onDragExit();                                                                      
3277                                                                                                          
3278         // Here we store the final page that will be dropped to, if the workspace in fact                
3279         // receives the drop                                                                             
3280         if (mInScrollArea) {                                                                             
3281             if (isPageMoving()) {                                                                        
3282                 // If the user drops while the page is scrolling, we should use that page as the         
3283                 // destination instead of the page that is being hovered over.                           
3284                 mDropToLayout = (CellLayout) getPageAt(getNextPage());                                   
3285             } else {                                                                                     
3286                 mDropToLayout = mDragOverlappingLayout;                                                  
3287             }                                                                                            
3288         } else {                                                                                         
3289             mDropToLayout = mDragTargetLayout;                                                           
3290         }                                                                                                
3291                                                                                                          
3292         if (mDragMode == DRAG_MODE_CREATE_FOLDER) {                                                      
3293             mCreateUserFolderOnDrop = true;                                                              
3294         } else if (mDragMode == DRAG_MODE_ADD_TO_FOLDER) {                                               
3295             mAddToExistingFolderOnDrop = true;                                                           
3296         }                                                                                                
3297                                                                                                          
3298         // Reset the scroll area and previous drag target                                                
3299         onResetScrollArea();                                                                             
3300         setCurrentDropLayout(null);                                                                      
3301         setCurrentDragOverlappingLayout(null);                                                           
3302                                                                                                          
3303         mSpringLoadedDragController.cancel();                                                            
3304                                                                                                          
3305         if (!mIsPageMoving) {                                                                            
3306             hideOutlines();                                                                              
3307         }                                                                                                
3308         mLauncher.getDragLayer().hidePageHints();                                                        
3309     }                                                                                                    
3310                                                                                                          
3311     void setCurrentDropLayout(CellLayout layout) {                                                       
3312         if (mDragTargetLayout != null) {                                                                 
3313             mDragTargetLayout.revertTempState();                                                         
3314             mDragTargetLayout.onDragExit();                                                              
3315         }                                                                                                
3316         mDragTargetLayout = layout;                                                                      
3317         if (mDragTargetLayout != null) {                                                                 
3318             mDragTargetLayout.onDragEnter();                                                             
3319         }                                                                                                
3320         cleanupReorder(true);                                                                            
3321         cleanupFolderCreation();                                                                         
3322         setCurrentDropOverCell(-1, -1);                                                                  
3323     }                                                                                                    
3324                                                                                                          
3325     void setCurrentDragOverlappingLayout(CellLayout layout) {                                            
3326         if (mDragOverlappingLayout != null) {                                                            
3327             mDragOverlappingLayout.setIsDragOverlapping(false);                                          
3328         }                                                                                                
3329         mDragOverlappingLayout = layout;                                                                 
3330         if (mDragOverlappingLayout != null) {                                                            
3331             mDragOverlappingLayout.setIsDragOverlapping(true);                                           
3332         }                                                                                                
3333         invalidate();                                                                                    
3334     }                                                                                                    
3335                                                                                                          
3336     void setCurrentDropOverCell(int x, int y) {                                                          
3337         if (x != mDragOverX || y != mDragOverY) {                                                        
3338             mDragOverX = x;                                                                              
3339             mDragOverY = y;                                                                              
3340             setDragMode(DRAG_MODE_NONE);                                                                 
3341         }                                                                                                
3342     }                                                                                                    
3343                                                                                                          
3344     void setDragMode(int dragMode) {                                                                     
3345         if (dragMode != mDragMode) {                                                                     
3346             if (dragMode == DRAG_MODE_NONE) {                                                            
3347                 cleanupAddToFolder();                                                                    
3348                 // We don't want to cancel the re-order alarm every time the target cell changes         
3349                 // as this feels to slow / unresponsive.                                                 
3350                 cleanupReorder(false);                                                                   
3351                 cleanupFolderCreation();                                                                 
3352             } else if (dragMode == DRAG_MODE_ADD_TO_FOLDER) {                                            
3353                 cleanupReorder(true);                                                                    
3354                 cleanupFolderCreation();                                                                 
3355             } else if (dragMode == DRAG_MODE_CREATE_FOLDER) {                                            
3356                 cleanupAddToFolder();                                                                    
3357                 cleanupReorder(true);                                                                    
3358             } else if (dragMode == DRAG_MODE_REORDER) {                                                  
3359                 cleanupAddToFolder();                                                                    
3360                 cleanupFolderCreation();                                                                 
3361             }                                                                                            
3362             mDragMode = dragMode;                                                                        
3363         }                                                                                                
3364     }                                                                                                    
3365                                                                                                          
3366     private void cleanupFolderCreation() {                                                               
3367         if (mDragFolderRingAnimator != null) {                                                           
3368             mDragFolderRingAnimator.animateToNaturalState();                                             
3369             mDragFolderRingAnimator = null;                                                              
3370         }                                                                                                
3371         mFolderCreationAlarm.setOnAlarmListener(null);                                                   
3372         mFolderCreationAlarm.cancelAlarm();                                                              
3373     }                                                                                                    
3374                                                                                                          
3375     private void cleanupAddToFolder() {                                                                  
3376         if (mDragOverFolderIcon != null) {                                                               
3377             mDragOverFolderIcon.onDragExit(null);                                                        
3378             mDragOverFolderIcon = null;                                                                  
3379         }                                                                                                
3380     }                                                                                                    
3381                                                                                                          
3382     private void cleanupReorder(boolean cancelAlarm) {                                                   
3383         // Any pending reorders are canceled                                                             
3384         if (cancelAlarm) {                                                                               
3385             mReorderAlarm.cancelAlarm();                                                                 
3386         }                                                                                                
3387         mLastReorderX = -1;                                                                              
3388         mLastReorderY = -1;                                                                              
3389     }                                                                                                    
3390                                                                                                          
3391    /*                                                                                                    
3392     *                                                                                                    
3393     * Convert the 2D coordinate xy from the parent View's coordinate space to this CellLayout's          
3394     * coordinate space. The argument xy is modified with the return result.                              
3395     *                                                                                                    
3396     * if cachedInverseMatrix is not null, this method will just use that matrix instead of               
3397     * computing it itself; we use this to avoid redundant matrix inversions in                           
3398     * findMatchingPageForDragOver                                                                        
3399     *                                                                                                    
3400     */                                                                                                   
3401    void mapPointFromSelfToChild(View v, float[] xy, Matrix cachedInverseMatrix) {                        
3402        xy[0] = xy[0] - v.getLeft();                                                                      
3403        xy[1] = xy[1] - v.getTop();                                                                       
3404    }                                                                                                     
3405                                                                                                          
3406    boolean isPointInSelfOverHotseat(int x, int y, Rect r) {                                              
3407        if (r == null) {                                                                                  
3408            r = new Rect();                                                                               
3409        }                                                                                                 
3410        mTempPt[0] = x;                                                                                   
3411        mTempPt[1] = y;                                                                                   
3412        mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempPt, true);                   
3413                                                                                                          
3414        LauncherAppState app = LauncherAppState.getInstance();                                            
3415        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                     
3416        r = grid.getHotseatRect();                                                                        
3417        if (r.contains(mTempPt[0], mTempPt[1])) {                                                         
3418            return true;                                                                                  
3419        }                                                                                                 
3420        return false;                                                                                     
3421    }                                                                                                     
3422                                                                                                          
3423    void mapPointFromSelfToHotseatLayout(Hotseat hotseat, float[] xy) {                                   
3424        mTempPt[0] = (int) xy[0];                                                                         
3425        mTempPt[1] = (int) xy[1];                                                                         
3426        mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempPt, true);                   
3427        mLauncher.getDragLayer().mapCoordInSelfToDescendent(hotseat.getLayout(), mTempPt);                
3428                                                                                                          
3429        xy[0] = mTempPt[0];                                                                               
3430        xy[1] = mTempPt[1];                                                                               
3431    }                                                                                                     
3432                                                                                                          
3433    /*                                                                                                    
3434     *                                                                                                    
3435     * Convert the 2D coordinate xy from this CellLayout's coordinate space to                            
3436     * the parent View's coordinate space. The argument xy is modified with the return result.            
3437     *                                                                                                    
3438     */                                                                                                   
3439    void mapPointFromChildToSelf(View v, float[] xy) {                                                    
3440        xy[0] += v.getLeft();                                                                             
3441        xy[1] += v.getTop();                                                                              
3442    }                                                                                                     
3443                                                                                                          
3444    static private float squaredDistance(float[] point1, float[] point2) {                                
3445         float distanceX = point1[0] - point2[0];                                                         
3446         float distanceY = point2[1] - point2[1];                                                         
3447         return distanceX * distanceX + distanceY * distanceY;                                            
3448    }                                                                                                     
3449                                                                                                          
3450     /*                                                                                                   
3451      *                                                                                                   
3452      * This method returns the CellLayout that is currently being dragged to. In order to drag           
3453      * to a CellLayout, either the touch point must be directly over the CellLayout, or as a second      
3454      * strategy, we see if the dragView is overlapping any CellLayout and choose the closest one         
3455      *                                                                                                   
3456      * Return null if no CellLayout is currently being dragged over                                      
3457      *                                                                                                   
3458      */                                                                                                  
3459     private CellLayout findMatchingPageForDragOver(                                                      
3460             DragView dragView, float originX, float originY, boolean exact) {                            
3461         // We loop through all the screens (ie CellLayouts) and see which ones overlap                   
3462         // with the item being dragged and then choose the one that's closest to the touch point         
3463         final int screenCount = getChildCount();                                                         
3464         CellLayout bestMatchingScreen = null;                                                            
3465         float smallestDistSoFar = Float.MAX_VALUE;                                                       
3466                                                                                                          
3467         for (int i = 0; i < screenCount; i++) {                                                          
3468             // The custom content screen is not a valid drag over option                                 
3469             if (mScreenOrder.get(i) == CUSTOM_CONTENT_SCREEN_ID) {                                       
3470                 continue;                                                                                
3471             }                                                                                            
3472                                                                                                          
3473             CellLayout cl = (CellLayout) getChildAt(i);                                                  
3474                                                                                                          
3475             final float[] touchXy = {originX, originY};                                                  
3476             // Transform the touch coordinates to the CellLayout's local coordinates                     
3477             // If the touch point is within the bounds of the cell layout, we can return immediately     
3478             cl.getMatrix().invert(mTempInverseMatrix);                                                   
3479             mapPointFromSelfToChild(cl, touchXy, mTempInverseMatrix);                                    
3480                                                                                                          
3481             if (touchXy[0] >= 0 && touchXy[0] <= cl.getWidth() &&                                        
3482                     touchXy[1] >= 0 && touchXy[1] <= cl.getHeight()) {                                   
3483                 return cl;                                                                               
3484             }                                                                                            
3485                                                                                                          
3486             if (!exact) {                                                                                
3487                 // Get the center of the cell layout in screen coordinates                               
3488                 final float[] cellLayoutCenter = mTempCellLayoutCenterCoordinates;                       
3489                 cellLayoutCenter[0] = cl.getWidth()/2;                                                   
3490                 cellLayoutCenter[1] = cl.getHeight()/2;                                                  
3491                 mapPointFromChildToSelf(cl, cellLayoutCenter);                                           
3492                                                                                                          
3493                 touchXy[0] = originX;                                                                    
3494                 touchXy[1] = originY;                                                                    
3495                                                                                                          
3496                 // Calculate the distance between the center of the CellLayout                           
3497                 // and the touch point                                                                   
3498                 float dist = squaredDistance(touchXy, cellLayoutCenter);                                 
3499                                                                                                          
3500                 if (dist < smallestDistSoFar) {                                                          
3501                     smallestDistSoFar = dist;                                                            
3502                     bestMatchingScreen = cl;                                                             
3503                 }                                                                                        
3504             }                                                                                            
3505         }                                                                                                
3506         return bestMatchingScreen;                                                                       
3507     }                                                                                                    
3508                                                                                                          
3509     // This is used to compute the visual center of the dragView. This point is then                     
3510     // used to visualize drop locations and determine where to drop an item. The idea is that            
3511     // the visual center represents the user's interpretation of where the item is, and hence            
3512     // is the appropriate point to use when determining drop location.                                   
3513     private float[] getDragViewVisualCenter(int x, int y, int xOffset, int yOffset,                      
3514             DragView dragView, float[] recycle) {                                                        
3515         float res[];                                                                                     
3516         if (recycle == null) {                                                                           
3517             res = new float[2];                                                                          
3518         } else {                                                                                         
3519             res = recycle;                                                                               
3520         }                                                                                                
3521                                                                                                          
3522         // First off, the drag view has been shifted in a way that is not represented in the             
3523         // x and y values or the x/yOffsets. Here we account for that shift.                             
3524         x += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetX);                              
3525         y += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY);                              
3526                                                                                                          
3527         // These represent the visual top and left of drag view if a dragRect was provided.              
3528         // If a dragRect was not provided, then they correspond to the actual view left and              
3529         // top, as the dragRect is in that case taken to be the entire dragView.                         
3530         // R.dimen.dragViewOffsetY.                                                                      
3531         int left = x - xOffset;                                                                          
3532         int top = y - yOffset;                                                                           
3533                                                                                                          
3534         // In order to find the visual center, we shift by half the dragRect                             
3535         res[0] = left + dragView.getDragRegion().width() / 2;                                            
3536         res[1] = top + dragView.getDragRegion().height() / 2;                                            
3537                                                                                                          
3538         return res;                                                                                      
3539     }                                                                                                    
3540                                                                                                          
3541     private boolean isDragWidget(DragObject d) {                                                         
3542         return (d.dragInfo instanceof LauncherAppWidgetInfo ||                                           
3543                 d.dragInfo instanceof PendingAddWidgetInfo);                                             
3544     }                                                                                                    
3545     private boolean isExternalDragWidget(DragObject d) {                                                 
3546         return d.dragSource != this && isDragWidget(d);                                                  
3547     }                                                                                                    
3548                                                                                                          
3549     public void onDragOver(DragObject d) {                                                               
3550         // Skip drag over events while we are dragging over side pages                                   
3551         if (mInScrollArea || !transitionStateShouldAllowDrop()) return;                                  
3552                                                                                                          
3553         Rect r = new Rect();                                                                             
3554         CellLayout layout = null;                                                                        
3555         ItemInfo item = (ItemInfo) d.dragInfo;                                                           
3556         if (item == null) {                                                                              
3557             if (LauncherAppState.isDogfoodBuild()) {                                                     
3558                 throw new NullPointerException("DragObject has null info");                              
3559             }                                                                                            
3560             return;                                                                                      
3561         }                                                                                                
3562                                                                                                          
3563         // Ensure that we have proper spans for the item that we are dropping                            
3564         if (item.spanX < 0 || item.spanY < 0) throw new RuntimeException("Improper spans found");        
3565         mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset,                  
3566             d.dragView, mDragViewVisualCenter);                                                          
3567                                                                                                          
3568         final View child = (mDragInfo == null) ? null : mDragInfo.cell;                                  
3569         // Identify whether we have dragged over a side page                                             
3570         if (workspaceInModalState()) {                                                                   
3571             if (mLauncher.getHotseat() != null && !isExternalDragWidget(d)) {                            
3572                 if (isPointInSelfOverHotseat(d.x, d.y, r)) {                                             
3573                     layout = mLauncher.getHotseat().getLayout();                                         
3574                 }                                                                                        
3575             }                                                                                            
3576             if (layout == null) {                                                                        
3577                 layout = findMatchingPageForDragOver(d.dragView, d.x, d.y, false);                       
3578             }                                                                                            
3579             if (layout != mDragTargetLayout) {                                                           
3580                 setCurrentDropLayout(layout);                                                            
3581                 setCurrentDragOverlappingLayout(layout);                                                 
3582                                                                                                          
3583                 boolean isInSpringLoadedMode = (mState == State.SPRING_LOADED);                          
3584                 if (isInSpringLoadedMode) {                                                              
3585                     if (mLauncher.isHotseatLayout(layout)) {                                             
3586                         mSpringLoadedDragController.cancel();                                            
3587                     } else {                                                                             
3588                         mSpringLoadedDragController.setAlarm(mDragTargetLayout);                         
3589                     }                                                                                    
3590                 }                                                                                        
3591             }                                                                                            
3592         } else {                                                                                         
3593             // Test to see if we are over the hotseat otherwise just use the current page                
3594             if (mLauncher.getHotseat() != null && !isDragWidget(d)) {                                    
3595                 if (isPointInSelfOverHotseat(d.x, d.y, r)) {                                             
3596                     layout = mLauncher.getHotseat().getLayout();                                         
3597                 }                                                                                        
3598             }                                                                                            
3599             if (layout == null) {                                                                        
3600                 layout = getCurrentDropLayout();                                                         
3601             }                                                                                            
3602             if (layout != mDragTargetLayout) {                                                           
3603                 setCurrentDropLayout(layout);                                                            
3604                 setCurrentDragOverlappingLayout(layout);                                                 
3605             }                                                                                            
3606         }                                                                                                
3607                                                                                                          
3608         // Handle the drag over                                                                          
3609         if (mDragTargetLayout != null) {                                                                 
3610             // We want the point to be mapped to the dragTarget.                                         
3611             if (mLauncher.isHotseatLayout(mDragTargetLayout)) {                                          
3612                 mapPointFromSelfToHotseatLayout(mLauncher.getHotseat(), mDragViewVisualCenter);          
3613             } else {                                                                                     
3614                 mapPointFromSelfToChild(mDragTargetLayout, mDragViewVisualCenter, null);                 
3615             }                                                                                            
3616                                                                                                          
3617             ItemInfo info = (ItemInfo) d.dragInfo;                                                       
3618                                                                                                          
3619             int minSpanX = item.spanX;                                                                   
3620             int minSpanY = item.spanY;                                                                   
3621             if (item.minSpanX > 0 && item.minSpanY > 0) {                                                
3622                 minSpanX = item.minSpanX;                                                                
3623                 minSpanY = item.minSpanY;                                                                
3624             }                                                                                            
3625                                                                                                          
3626             mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],                                
3627                     (int) mDragViewVisualCenter[1], minSpanX, minSpanY,                                  
3628                     mDragTargetLayout, mTargetCell);                                                     
3629             int reorderX = mTargetCell[0];                                                               
3630             int reorderY = mTargetCell[1];                                                               
3631                                                                                                          
3632             setCurrentDropOverCell(mTargetCell[0], mTargetCell[1]);                                      
3633                                                                                                          
3634             float targetCellDistance = mDragTargetLayout.getDistanceFromCell(                            
3635                     mDragViewVisualCenter[0], mDragViewVisualCenter[1], mTargetCell);                    
3636                                                                                                          
3637             final View dragOverView = mDragTargetLayout.getChildAt(mTargetCell[0],                       
3638                     mTargetCell[1]);                                                                     
3639                                                                                                          
3640             manageFolderFeedback(info, mDragTargetLayout, mTargetCell,                                   
3641                     targetCellDistance, dragOverView);                                                   
3642                                                                                                          
3643             boolean nearestDropOccupied = mDragTargetLayout.isNearestDropLocationOccupied((int)          
3644                     mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], item.spanX,                
3645                     item.spanY, child, mTargetCell);                                                     
3646                                                                                                          
3647             if (!nearestDropOccupied) {                                                                  
3648                 mDragTargetLayout.visualizeDropLocation(child, mDragOutline,                             
3649                         (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1],                  
3650                         mTargetCell[0], mTargetCell[1], item.spanX, item.spanY, false,                   
3651                         d.dragView.getDragVisualizeOffset(), d.dragView.getDragRegion());                
3652             } else if ((mDragMode == DRAG_MODE_NONE || mDragMode == DRAG_MODE_REORDER)                   
3653                     && !mReorderAlarm.alarmPending() && (mLastReorderX != reorderX ||                    
3654                     mLastReorderY != reorderY)) {                                                        
3655                                                                                                          
3656                 int[] resultSpan = new int[2];                                                           
3657                 mDragTargetLayout.performReorder((int) mDragViewVisualCenter[0],                         
3658                         (int) mDragViewVisualCenter[1], minSpanX, minSpanY, item.spanX, item.spanY,      
3659                         child, mTargetCell, resultSpan, CellLayout.MODE_SHOW_REORDER_HINT);              
3660                                                                                                          
3661                 // Otherwise, if we aren't adding to or creating a folder and there's no pending         
3662                 // reorder, then we schedule a reorder                                                   
3663                 ReorderAlarmListener listener = new ReorderAlarmListener(mDragViewVisualCenter,          
3664                         minSpanX, minSpanY, item.spanX, item.spanY, d.dragView, child);                  
3665                 mReorderAlarm.setOnAlarmListener(listener);                                              
3666                 mReorderAlarm.setAlarm(REORDER_TIMEOUT);                                                 
3667             }                                                                                            
3668                                                                                                          
3669             if (mDragMode == DRAG_MODE_CREATE_FOLDER || mDragMode == DRAG_MODE_ADD_TO_FOLDER ||          
3670                     !nearestDropOccupied) {                                                              
3671                 if (mDragTargetLayout != null) {                                                         
3672                     mDragTargetLayout.revertTempState();                                                 
3673                 }                                                                                        
3674             }                                                                                            
3675         }                                                                                                
3676     }                                                                                                    
3677                                                                                                          
3678     private void manageFolderFeedback(ItemInfo info, CellLayout targetLayout,                            
3679             int[] targetCell, float distance, View dragOverView) {                                       
3680         boolean userFolderPending = willCreateUserFolder(info, targetLayout, targetCell, distance,       
3681                 false);                                                                                  
3682                                                                                                          
3683         if (mDragMode == DRAG_MODE_NONE && userFolderPending &&                                          
3684                 !mFolderCreationAlarm.alarmPending()) {                                                  
3685             mFolderCreationAlarm.setOnAlarmListener(new                                                  
3686                     FolderCreationAlarmListener(targetLayout, targetCell[0], targetCell[1]));            
3687             mFolderCreationAlarm.setAlarm(FOLDER_CREATION_TIMEOUT);                                      
3688             return;                                                                                      
3689         }                                                                                                
3690                                                                                                          
3691         boolean willAddToFolder =                                                                        
3692                 willAddToExistingUserFolder(info, targetLayout, targetCell, distance);                   
3693                                                                                                          
3694         if (willAddToFolder && mDragMode == DRAG_MODE_NONE) {                                            
3695             mDragOverFolderIcon = ((FolderIcon) dragOverView);                                           
3696             mDragOverFolderIcon.onDragEnter(info);                                                       
3697             if (targetLayout != null) {                                                                  
3698                 targetLayout.clearDragOutlines();                                                        
3699             }                                                                                            
3700             setDragMode(DRAG_MODE_ADD_TO_FOLDER);                                                        
3701             return;                                                                                      
3702         }                                                                                                
3703                                                                                                          
3704         if (mDragMode == DRAG_MODE_ADD_TO_FOLDER && !willAddToFolder) {                                  
3705             setDragMode(DRAG_MODE_NONE);                                                                 
3706         }                                                                                                
3707         if (mDragMode == DRAG_MODE_CREATE_FOLDER && !userFolderPending) {                                
3708             setDragMode(DRAG_MODE_NONE);                                                                 
3709         }                                                                                                
3710                                                                                                          
3711         return;                                                                                          
3712     }                                                                                                    
3713                                                                                                          
3714     class FolderCreationAlarmListener implements OnAlarmListener {                                       
3715         CellLayout layout;                                                                               
3716         int cellX;                                                                                       
3717         int cellY;                                                                                       
3718                                                                                                          
3719         public FolderCreationAlarmListener(CellLayout layout, int cellX, int cellY) {                    
3720             this.layout = layout;                                                                        
3721             this.cellX = cellX;                                                                          
3722             this.cellY = cellY;                                                                          
3723         }                                                                                                
3724                                                                                                          
3725         public void onAlarm(Alarm alarm) {                                                               
3726             if (mDragFolderRingAnimator != null) {                                                       
3727                 // This shouldn't happen ever, but just in case, make sure we clean up the mess.         
3728                 mDragFolderRingAnimator.animateToNaturalState();                                         
3729             }                                                                                            
3730             mDragFolderRingAnimator = new FolderRingAnimator(mLauncher, null);                           
3731             mDragFolderRingAnimator.setCell(cellX, cellY);                                               
3732             mDragFolderRingAnimator.setCellLayout(layout);                                               
3733             mDragFolderRingAnimator.animateToAcceptState();                                              
3734             layout.showFolderAccept(mDragFolderRingAnimator);                                            
3735             layout.clearDragOutlines();                                                                  
3736             setDragMode(DRAG_MODE_CREATE_FOLDER);                                                        
3737         }                                                                                                
3738     }                                                                                                    
3739                                                                                                          
3740     class ReorderAlarmListener implements OnAlarmListener {                                              
3741         float[] dragViewCenter;                                                                          
3742         int minSpanX, minSpanY, spanX, spanY;                                                            
3743         DragView dragView;                                                                               
3744         View child;                                                                                      
3745                                                                                                          
3746         public ReorderAlarmListener(float[] dragViewCenter, int minSpanX, int minSpanY, int spanX,       
3747                 int spanY, DragView dragView, View child) {                                              
3748             this.dragViewCenter = dragViewCenter;                                                        
3749             this.minSpanX = minSpanX;                                                                    
3750             this.minSpanY = minSpanY;                                                                    
3751             this.spanX = spanX;                                                                          
3752             this.spanY = spanY;                                                                          
3753             this.child = child;                                                                          
3754             this.dragView = dragView;                                                                    
3755         }                                                                                                
3756                                                                                                          
3757         public void onAlarm(Alarm alarm) {                                                               
3758             int[] resultSpan = new int[2];                                                               
3759             mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],                                
3760                     (int) mDragViewVisualCenter[1], minSpanX, minSpanY, mDragTargetLayout,               
3761                     mTargetCell);                                                                        
3762             mLastReorderX = mTargetCell[0];                                                              
3763             mLastReorderY = mTargetCell[1];                                                              
3764                                                                                                          
3765             mTargetCell = mDragTargetLayout.performReorder((int) mDragViewVisualCenter[0],               
3766                 (int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY,                        
3767                 child, mTargetCell, resultSpan, CellLayout.MODE_DRAG_OVER);                              
3768                                                                                                          
3769             if (mTargetCell[0] < 0 || mTargetCell[1] < 0) {                                              
3770                 mDragTargetLayout.revertTempState();                                                     
3771             } else {                                                                                     
3772                 setDragMode(DRAG_MODE_REORDER);                                                          
3773             }                                                                                            
3774                                                                                                          
3775             boolean resize = resultSpan[0] != spanX || resultSpan[1] != spanY;                           
3776             mDragTargetLayout.visualizeDropLocation(child, mDragOutline,                                 
3777                 (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1],                          
3778                 mTargetCell[0], mTargetCell[1], resultSpan[0], resultSpan[1], resize,                    
3779                 dragView.getDragVisualizeOffset(), dragView.getDragRegion());                            
3780         }                                                                                                
3781     }                                                                                                    
3782                                                                                                          
3783     @Override                                                                                            
3784     public void getHitRectRelativeToDragLayer(Rect outRect) {                                            
3785         // We want the workspace to have the whole area of the display (it will find the correct         
3786         // cell layout to drop to in the existing drag/drop logic.                                       
3787         mLauncher.getDragLayer().getDescendantRectRelativeToSelf(this, outRect);                         
3788     }                                                                                                    
3789                                                                                                          
3790     /**                                                                                                  
3791      * Add the item specified by dragInfo to the given layout.                                           
3792      * @return true if successful                                                                        
3793      */                                                                                                  
3794     public boolean addExternalItemToScreen(ItemInfo dragInfo, CellLayout layout) {                       
3795         if (layout.findCellForSpan(mTempEstimate, dragInfo.spanX, dragInfo.spanY)) {                     
3796             onDropExternal(dragInfo.dropPos, (ItemInfo) dragInfo, (CellLayout) layout, false);           
3797             return true;                                                                                 
3798         }                                                                                                
3799         mLauncher.showOutOfSpaceMessage(mLauncher.isHotseatLayout(layout));                              
3800         return false;                                                                                    
3801     }                                                                                                    
3802                                                                                                          
3803     private void onDropExternal(int[] touchXY, Object dragInfo,                                          
3804             CellLayout cellLayout, boolean insertAtFirst) {                                              
3805         onDropExternal(touchXY, dragInfo, cellLayout, insertAtFirst, null);                              
3806     }                                                                                                    
3807                                                                                                          
3808     /**                                                                                                  
3809      * Drop an item that didn't originate on one of the workspace screens.                               
3810      * It may have come from Launcher (e.g. from all apps or customize), or it may have                  
3811      * come from another app altogether.                                                                 
3812      *                                                                                                   
3813      * NOTE: This can also be called when we are outside of a drag event, when we want                   
3814      * to add an item to one of the workspace screens.                                                   
3815      */                                                                                                  
3816     private void onDropExternal(final int[] touchXY, final Object dragInfo,                              
3817             final CellLayout cellLayout, boolean insertAtFirst, DragObject d) {                          
3818         final Runnable exitSpringLoadedRunnable = new Runnable() {                                       
3819             @Override                                                                                    
3820             public void run() {                                                                          
3821                 mLauncher.exitSpringLoadedDragModeDelayed(true,                                          
3822                         Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);                            
3823             }                                                                                            
3824         };                                                                                               
3825                                                                                                          
3826         ItemInfo info = (ItemInfo) dragInfo;                                                             
3827         int spanX = info.spanX;                                                                          
3828         int spanY = info.spanY;                                                                          
3829         if (mDragInfo != null) {                                                                         
3830             spanX = mDragInfo.spanX;                                                                     
3831             spanY = mDragInfo.spanY;                                                                     
3832         }                                                                                                
3833                                                                                                          
3834         final long container = mLauncher.isHotseatLayout(cellLayout) ?                                   
3835                 LauncherSettings.Favorites.CONTAINER_HOTSEAT :                                           
3836                     LauncherSettings.Favorites.CONTAINER_DESKTOP;                                        
3837         final long screenId = getIdForScreen(cellLayout);                                                
3838         if (!mLauncher.isHotseatLayout(cellLayout)                                                       
3839                 && screenId != getScreenIdForPageIndex(mCurrentPage)                                     
3840                 && mState != State.SPRING_LOADED) {                                                      
3841             snapToScreenId(screenId, null);                                                              
3842         }                                                                                                
3843                                                                                                          
3844         if (info instanceof PendingAddItemInfo) {                                                        
3845             final PendingAddItemInfo pendingInfo = (PendingAddItemInfo) dragInfo;                        
3846                                                                                                          
3847             boolean findNearestVacantCell = true;                                                        
3848             if (pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {                 
3849                 mTargetCell = findNearestArea((int) touchXY[0], (int) touchXY[1], spanX, spanY,          
3850                         cellLayout, mTargetCell);                                                        
3851                 float distance = cellLayout.getDistanceFromCell(mDragViewVisualCenter[0],                
3852                         mDragViewVisualCenter[1], mTargetCell);                                          
3853                 if (willCreateUserFolder((ItemInfo) d.dragInfo, cellLayout, mTargetCell,                 
3854                         distance, true) || willAddToExistingUserFolder((ItemInfo) d.dragInfo,            
3855                                 cellLayout, mTargetCell, distance)) {                                    
3856                     findNearestVacantCell = false;                                                       
3857                 }                                                                                        
3858             }                                                                                            
3859                                                                                                          
3860             final ItemInfo item = (ItemInfo) d.dragInfo;                                                 
3861             boolean updateWidgetSize = false;                                                            
3862             if (findNearestVacantCell) {                                                                 
3863                 int minSpanX = item.spanX;                                                               
3864                 int minSpanY = item.spanY;                                                               
3865                 if (item.minSpanX > 0 && item.minSpanY > 0) {                                            
3866                     minSpanX = item.minSpanX;                                                            
3867                     minSpanY = item.minSpanY;                                                            
3868                 }                                                                                        
3869                 int[] resultSpan = new int[2];                                                           
3870                 mTargetCell = cellLayout.performReorder((int) mDragViewVisualCenter[0],                  
3871                         (int) mDragViewVisualCenter[1], minSpanX, minSpanY, info.spanX, info.spanY,      
3872                         null, mTargetCell, resultSpan, CellLayout.MODE_ON_DROP_EXTERNAL);                
3873                                                                                                          
3874                 if (resultSpan[0] != item.spanX || resultSpan[1] != item.spanY) {                        
3875                     updateWidgetSize = true;                                                             
3876                 }                                                                                        
3877                 item.spanX = resultSpan[0];                                                              
3878                 item.spanY = resultSpan[1];                                                              
3879             }                                                                                            
3880                                                                                                          
3881             Runnable onAnimationCompleteRunnable = new Runnable() {                                      
3882                 @Override                                                                                
3883                 public void run() {                                                                      
3884                     // Normally removeExtraEmptyScreen is called in Workspace#onDragEnd, but when        
3885                     // adding an item that may not be dropped right away (due to a config activity)      
3886                     // we defer the removal until the activity returns.                                  
3887                     deferRemoveExtraEmptyScreen();                                                       
3888                                                                                                          
3889                     // When dragging and dropping from customization tray, we deal with creating         
3890                     // widgets/shortcuts/folders in a slightly different way                             
3891                     switch (pendingInfo.itemType) {                                                      
3892                     case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                                 
3893                         int span[] = new int[2];                                                         
3894                         span[0] = item.spanX;                                                            
3895                         span[1] = item.spanY;                                                            
3896                         mLauncher.addAppWidgetFromDrop((PendingAddWidgetInfo) pendingInfo,               
3897                                 container, screenId, mTargetCell, span, null);                           
3898                         break;                                                                           
3899                     case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                  
3900                         mLauncher.processShortcutFromDrop(pendingInfo.componentName,                     
3901                                 container, screenId, mTargetCell, null);                                 
3902                         break;                                                                           
3903                     default:                                                                             
3904                         throw new IllegalStateException("Unknown item type: " +                          
3905                                 pendingInfo.itemType);                                                   
3906                     }                                                                                    
3907                 }                                                                                        
3908             };                                                                                           
3909             View finalView = pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET      
3910                     ? ((PendingAddWidgetInfo) pendingInfo).boundWidget : null;                           
3911                                                                                                          
3912             if (finalView instanceof AppWidgetHostView && updateWidgetSize) {                            
3913                 AppWidgetHostView awhv = (AppWidgetHostView) finalView;                                  
3914                 AppWidgetResizeFrame.updateWidgetSizeRanges(awhv, mLauncher, item.spanX,                 
3915                         item.spanY);                                                                     
3916             }                                                                                            
3917                                                                                                          
3918             int animationStyle = ANIMATE_INTO_POSITION_AND_DISAPPEAR;                                    
3919             if (pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET &&                
3920                     ((PendingAddWidgetInfo) pendingInfo).info.configure != null) {                       
3921                 animationStyle = ANIMATE_INTO_POSITION_AND_REMAIN;                                       
3922             }                                                                                            
3923             animateWidgetDrop(info, cellLayout, d.dragView, onAnimationCompleteRunnable,                 
3924                     animationStyle, finalView, true);                                                    
3925         } else {                                                                                         
3926             // This is for other drag/drop cases, like dragging from All Apps                            
3927             View view = null;                                                                            
3928                                                                                                          
3929             switch (info.itemType) {                                                                     
3930             case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                                       
3931             case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                          
3932                 if (info.container == NO_ID && info instanceof AppInfo) {                                
3933                     // Came from all apps -- make a copy                                                 
3934                     info = new ShortcutInfo((AppInfo) info);                                             
3935                 }                                                                                        
3936                 view = mLauncher.createShortcut(R.layout.application, cellLayout,                        
3937                         (ShortcutInfo) info);                                                            
3938                 break;                                                                                   
3939             case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                            
3940                 view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher, cellLayout,                   
3941                         (FolderInfo) info, mIconCache);                                                  
3942                 break;                                                                                   
3943             default:                                                                                     
3944                 throw new IllegalStateException("Unknown item type: " + info.itemType);                  
3945             }                                                                                            
3946                                                                                                          
3947             // First we find the cell nearest to point at which the item is                              
3948             // dropped, without any consideration to whether there is an item there.                     
3949             if (touchXY != null) {                                                                       
3950                 mTargetCell = findNearestArea((int) touchXY[0], (int) touchXY[1], spanX, spanY,          
3951                         cellLayout, mTargetCell);                                                        
3952                 float distance = cellLayout.getDistanceFromCell(mDragViewVisualCenter[0],                
3953                         mDragViewVisualCenter[1], mTargetCell);                                          
3954                 d.postAnimationRunnable = exitSpringLoadedRunnable;                                      
3955                 if (createUserFolderIfNecessary(view, container, cellLayout, mTargetCell, distance,      
3956                         true, d.dragView, d.postAnimationRunnable)) {                                    
3957                     return;                                                                              
3958                 }                                                                                        
3959                 if (addToExistingFolderIfNecessary(view, cellLayout, mTargetCell, distance, d,           
3960                         true)) {                                                                         
3961                     return;                                                                              
3962                 }                                                                                        
3963             }                                                                                            
3964                                                                                                          
3965             if (touchXY != null) {                                                                       
3966                 // when dragging and dropping, just find the closest free spot                           
3967                 mTargetCell = cellLayout.performReorder((int) mDragViewVisualCenter[0],                  
3968                         (int) mDragViewVisualCenter[1], 1, 1, 1, 1,                                      
3969                         null, mTargetCell, null, CellLayout.MODE_ON_DROP_EXTERNAL);                      
3970             } else {                                                                                     
3971                 cellLayout.findCellForSpan(mTargetCell, 1, 1);                                           
3972             }                                                                                            
3973             // Add the item to DB before adding to screen ensures that the container and other           
3974             // values of the info is properly updated.                                                   
3975             LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screenId,                  
3976                     mTargetCell[0], mTargetCell[1]);                                                     
3977                                                                                                          
3978             addInScreen(view, container, screenId, mTargetCell[0], mTargetCell[1], info.spanX,           
3979                     info.spanY, insertAtFirst);                                                          
3980             cellLayout.onDropChild(view);                                                                
3981             cellLayout.getShortcutsAndWidgets().measureChild(view);                                      
3982                                                                                                          
3983             if (d.dragView != null) {                                                                    
3984                 // We wrap the animation call in the temporary set and reset of the current              
3985                 // cellLayout to its final transform -- this means we animate the drag view to           
3986                 // the correct final location.                                                           
3987                 setFinalTransitionTransform(cellLayout);                                                 
3988                 mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, view,                       
3989                         exitSpringLoadedRunnable, this);                                                 
3990                 resetTransitionTransform(cellLayout);                                                    
3991             }                                                                                            
3992         }                                                                                                
3993     }                                                                                                    
3994                                                                                                          
3995     public Bitmap createWidgetBitmap(ItemInfo widgetInfo, View layout) {                                 
3996         int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(widgetInfo.spanX,                 
3997                 widgetInfo.spanY, widgetInfo, false);                                                    
3998         int visibility = layout.getVisibility();                                                         
3999         layout.setVisibility(VISIBLE);                                                                   
4000                                                                                                          
4001         int width = MeasureSpec.makeMeasureSpec(unScaledSize[0], MeasureSpec.EXACTLY);                   
4002         int height = MeasureSpec.makeMeasureSpec(unScaledSize[1], MeasureSpec.EXACTLY);                  
4003         Bitmap b = Bitmap.createBitmap(unScaledSize[0], unScaledSize[1],                                 
4004                 Bitmap.Config.ARGB_8888);                                                                
4005         mCanvas.setBitmap(b);                                                                            
4006                                                                                                          
4007         layout.measure(width, height);                                                                   
4008         layout.layout(0, 0, unScaledSize[0], unScaledSize[1]);                                           
4009         layout.draw(mCanvas);                                                                            
4010         mCanvas.setBitmap(null);                                                                         
4011         layout.setVisibility(visibility);                                                                
4012         return b;                                                                                        
4013     }                                                                                                    
4014                                                                                                          
4015     private void getFinalPositionForDropAnimation(int[] loc, float[] scaleXY,                            
4016             DragView dragView, CellLayout layout, ItemInfo info, int[] targetCell,                       
4017             boolean external, boolean scale) {                                                           
4018         // Now we animate the dragView, (ie. the widget or shortcut preview) into its final              
4019         // location and size on the home screen.                                                         
4020         int spanX = info.spanX;                                                                          
4021         int spanY = info.spanY;                                                                          
4022                                                                                                          
4023         Rect r = estimateItemPosition(layout, info, targetCell[0], targetCell[1], spanX, spanY);         
4024         loc[0] = r.left;                                                                                 
4025         loc[1] = r.top;                                                                                  
4026                                                                                                          
4027         setFinalTransitionTransform(layout);                                                             
4028         float cellLayoutScale =                                                                          
4029                 mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(layout, loc, true);            
4030         resetTransitionTransform(layout);                                                                
4031                                                                                                          
4032         float dragViewScaleX;                                                                            
4033         float dragViewScaleY;                                                                            
4034         if (scale) {                                                                                     
4035             dragViewScaleX = (1.0f * r.width()) / dragView.getMeasuredWidth();                           
4036             dragViewScaleY = (1.0f * r.height()) / dragView.getMeasuredHeight();                         
4037         } else {                                                                                         
4038             dragViewScaleX = 1f;                                                                         
4039             dragViewScaleY = 1f;                                                                         
4040         }                                                                                                
4041                                                                                                          
4042         // The animation will scale the dragView about its center, so we need to center about            
4043         // the final location.                                                                           
4044         loc[0] -= (dragView.getMeasuredWidth() - cellLayoutScale * r.width()) / 2;                       
4045         loc[1] -= (dragView.getMeasuredHeight() - cellLayoutScale * r.height()) / 2;                     
4046                                                                                                          
4047         scaleXY[0] = dragViewScaleX * cellLayoutScale;                                                   
4048         scaleXY[1] = dragViewScaleY * cellLayoutScale;                                                   
4049     }                                                                                                    
4050                                                                                                          
4051     public void animateWidgetDrop(ItemInfo info, CellLayout cellLayout, DragView dragView,               
4052             final Runnable onCompleteRunnable, int animationType, final View finalView,                  
4053             boolean external) {                                                                          
4054         Rect from = new Rect();                                                                          
4055         mLauncher.getDragLayer().getViewRectRelativeToSelf(dragView, from);                              
4056                                                                                                          
4057         int[] finalPos = new int[2];                                                                     
4058         float scaleXY[] = new float[2];                                                                  
4059         boolean scalePreview = !(info instanceof PendingAddShortcutInfo);                                
4060         getFinalPositionForDropAnimation(finalPos, scaleXY, dragView, cellLayout, info, mTargetCell,     
4061                 external, scalePreview);                                                                 
4062                                                                                                          
4063         Resources res = mLauncher.getResources();                                                        
4064         final int duration = res.getInteger(R.integer.config_dropAnimMaxDuration) - 200;                 
4065                                                                                                          
4066         // In the case where we've prebound the widget, we remove it from the DragLayer                  
4067         if (finalView instanceof AppWidgetHostView && external) {                                        
4068             Log.d(TAG, "6557954 Animate widget drop, final view is appWidgetHostView");                  
4069             mLauncher.getDragLayer().removeView(finalView);                                              
4070         }                                                                                                
4071         if ((animationType == ANIMATE_INTO_POSITION_AND_RESIZE || external) && finalView != null) {      
4072             Bitmap crossFadeBitmap = createWidgetBitmap(info, finalView);                                
4073             dragView.setCrossFadeBitmap(crossFadeBitmap);                                                
4074             dragView.crossFade((int) (duration * 0.8f));                                                 
4075         } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET && external) {        
4076             scaleXY[0] = scaleXY[1] = Math.min(scaleXY[0],  scaleXY[1]);                                 
4077         }                                                                                                
4078                                                                                                          
4079         DragLayer dragLayer = mLauncher.getDragLayer();                                                  
4080         if (animationType == CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION) {                                   
4081             mLauncher.getDragLayer().animateViewIntoPosition(dragView, finalPos, 0f, 0.1f, 0.1f,         
4082                     DragLayer.ANIMATION_END_DISAPPEAR, onCompleteRunnable, duration);                    
4083         } else {                                                                                         
4084             int endStyle;                                                                                
4085             if (animationType == ANIMATE_INTO_POSITION_AND_REMAIN) {                                     
4086                 endStyle = DragLayer.ANIMATION_END_REMAIN_VISIBLE;                                       
4087             } else {                                                                                     
4088                 endStyle = DragLayer.ANIMATION_END_DISAPPEAR;;                                           
4089             }                                                                                            
4090                                                                                                          
4091             Runnable onComplete = new Runnable() {                                                       
4092                 @Override                                                                                
4093                 public void run() {                                                                      
4094                     if (finalView != null) {                                                             
4095                         finalView.setVisibility(VISIBLE);                                                
4096                     }                                                                                    
4097                     if (onCompleteRunnable != null) {                                                    
4098                         onCompleteRunnable.run();                                                        
4099                     }                                                                                    
4100                 }                                                                                        
4101             };                                                                                           
4102             dragLayer.animateViewIntoPosition(dragView, from.left, from.top, finalPos[0],                
4103                     finalPos[1], 1, 1, 1, scaleXY[0], scaleXY[1], onComplete, endStyle,                  
4104                     duration, this);                                                                     
4105         }                                                                                                
4106     }                                                                                                    
4107                                                                                                          
4108     public void setFinalTransitionTransform(CellLayout layout) {                                         
4109         if (isSwitchingState()) {                                                                        
4110             mCurrentScale = getScaleX();                                                                 
4111             setScaleX(mNewScale);                                                                        
4112             setScaleY(mNewScale);                                                                        
4113         }                                                                                                
4114     }                                                                                                    
4115     public void resetTransitionTransform(CellLayout layout) {                                            
4116         if (isSwitchingState()) {                                                                        
4117             setScaleX(mCurrentScale);                                                                    
4118             setScaleY(mCurrentScale);                                                                    
4119         }                                                                                                
4120     }                                                                                                    
4121                                                                                                          
4122     /**                                                                                                  
4123      * Return the current {@link CellLayout}, correctly picking the destination                          
4124      * screen while a scroll is in progress.                                                             
4125      */                                                                                                  
4126     public CellLayout getCurrentDropLayout() {                                                           
4127         return (CellLayout) getChildAt(getNextPage());                                                   
4128     }                                                                                                    
4129                                                                                                          
4130     /**                                                                                                  
4131      * Return the current CellInfo describing our current drag; this method exists                       
4132      * so that Launcher can sync this object with the correct info when the activity is created/         
4133      * destroyed                                                                                         
4134      *                                                                                                   
4135      */                                                                                                  
4136     public CellLayout.CellInfo getDragInfo() {                                                           
4137         return mDragInfo;                                                                                
4138     }                                                                                                    
4139                                                                                                          
4140     public int getCurrentPageOffsetFromCustomContent() {                                                 
4141         return getNextPage() - numCustomPages();                                                         
4142     }                                                                                                    
4143                                                                                                          
4144     /**                                                                                                  
4145      * Calculate the nearest cell where the given object would be dropped.                               
4146      *                                                                                                   
4147      * pixelX and pixelY should be in the coordinate system of layout                                    
4148      */                                                                                                  
4149     private int[] findNearestArea(int pixelX, int pixelY,                                                
4150             int spanX, int spanY, CellLayout layout, int[] recycle) {                                    
4151         return layout.findNearestArea(                                                                   
4152                 pixelX, pixelY, spanX, spanY, recycle);                                                  
4153     }                                                                                                    
4154                                                                                                          
4155     void setup(DragController dragController) {                                                          
4156         mSpringLoadedDragController = new SpringLoadedDragController(mLauncher);                         
4157         mDragController = dragController;                                                                
4158                                                                                                          
4159         // hardware layers on children are enabled on startup, but should be disabled until              
4160         // needed                                                                                        
4161         updateChildrenLayersEnabled(false);                                                              
4162     }                                                                                                    
4163                                                                                                          
4164     /**                                                                                                  
4165      * Called at the end of a drag which originated on the workspace.                                    
4166      */                                                                                                  
4167     public void onDropCompleted(final View target, final DragObject d,                                   
4168             final boolean isFlingToDelete, final boolean success) {                                      
4169         if (mDeferDropAfterUninstall) {                                                                  
4170             mDeferredAction = new Runnable() {                                                           
4171                 public void run() {                                                                      
4172                     onDropCompleted(target, d, isFlingToDelete, success);                                
4173                     mDeferredAction = null;                                                              
4174                 }                                                                                        
4175             };                                                                                           
4176             return;                                                                                      
4177         }                                                                                                
4178                                                                                                          
4179         boolean beingCalledAfterUninstall = mDeferredAction != null;                                     
4180                                                                                                          
4181         if (success && !(beingCalledAfterUninstall && !mUninstallSuccessful)) {                          
4182             if (target != this && mDragInfo != null) {                                                   
4183                 CellLayout parentCell = getParentCellLayoutForView(mDragInfo.cell);                      
4184                 if (parentCell != null) {                                                                
4185                     parentCell.removeView(mDragInfo.cell);                                               
4186                 } else if (LauncherAppState.isDogfoodBuild()) {                                          
4187                     throw new NullPointerException("mDragInfo.cell has null parent");                    
4188                 }                                                                                        
4189                 if (mDragInfo.cell instanceof DropTarget) {                                              
4190                     mDragController.removeDropTarget((DropTarget) mDragInfo.cell);                       
4191                 }                                                                                        
4192             }                                                                                            
4193         } else if (mDragInfo != null) {                                                                  
4194             CellLayout cellLayout;                                                                       
4195             if (mLauncher.isHotseatLayout(target)) {                                                     
4196                 cellLayout = mLauncher.getHotseat().getLayout();                                         
4197             } else {                                                                                     
4198                 cellLayout = getScreenWithId(mDragInfo.screenId);                                        
4199             }                                                                                            
4200             if (cellLayout == null && LauncherAppState.isDogfoodBuild()) {                               
4201                 throw new RuntimeException("Invalid state: cellLayout == null in "                       
4202                         + "Workspace#onDropCompleted. Please file a bug. ");                             
4203             }                                                                                            
4204             if (cellLayout != null) {                                                                    
4205                 cellLayout.onDropChild(mDragInfo.cell);                                                  
4206             }                                                                                            
4207         }                                                                                                
4208         if ((d.cancelled || (beingCalledAfterUninstall && !mUninstallSuccessful))                        
4209                 && mDragInfo.cell != null) {                                                             
4210             mDragInfo.cell.setVisibility(VISIBLE);                                                       
4211         }                                                                                                
4212         mDragOutline = null;                                                                             
4213         mDragInfo = null;                                                                                
4214     }                                                                                                    
4215                                                                                                          
4216     public void deferCompleteDropAfterUninstallActivity() {                                              
4217         mDeferDropAfterUninstall = true;                                                                 
4218     }                                                                                                    
4219                                                                                                          
4220     /// maybe move this into a smaller part                                                              
4221     public void onUninstallActivityReturned(boolean success) {                                           
4222         mDeferDropAfterUninstall = false;                                                                
4223         mUninstallSuccessful = success;                                                                  
4224         if (mDeferredAction != null) {                                                                   
4225             mDeferredAction.run();                                                                       
4226         }                                                                                                
4227     }                                                                                                    
4228                                                                                                          
4229     void updateItemLocationsInDatabase(CellLayout cl) {                                                  
4230         int count = cl.getShortcutsAndWidgets().getChildCount();                                         
4231                                                                                                          
4232         long screenId = getIdForScreen(cl);                                                              
4233         int container = Favorites.CONTAINER_DESKTOP;                                                     
4234                                                                                                          
4235         if (mLauncher.isHotseatLayout(cl)) {                                                             
4236             screenId = -1;                                                                               
4237             container = Favorites.CONTAINER_HOTSEAT;                                                     
4238         }                                                                                                
4239                                                                                                          
4240         for (int i = 0; i < count; i++) {                                                                
4241             View v = cl.getShortcutsAndWidgets().getChildAt(i);                                          
4242             ItemInfo info = (ItemInfo) v.getTag();                                                       
4243             // Null check required as the AllApps button doesn't have an item info                       
4244             if (info != null && info.requiresDbUpdate) {                                                 
4245                 info.requiresDbUpdate = false;                                                           
4246                 LauncherModel.modifyItemInDatabase(mLauncher, info, container, screenId, info.cellX,     
4247                         info.cellY, info.spanX, info.spanY);                                             
4248             }                                                                                            
4249         }                                                                                                
4250     }                                                                                                    
4251                                                                                                          
4252     ArrayList<ComponentName> getUniqueComponents(boolean stripDuplicates, ArrayList<ComponentName> duplic🔵
4253         ArrayList<ComponentName> uniqueIntents = new ArrayList<ComponentName>();                         
4254         getUniqueIntents((CellLayout) mLauncher.getHotseat().getLayout(), uniqueIntents, duplicates, fals🔵
4255         int count = getChildCount();                                                                     
4256         for (int i = 0; i < count; i++) {                                                                
4257             CellLayout cl = (CellLayout) getChildAt(i);                                                  
4258             getUniqueIntents(cl, uniqueIntents, duplicates, false);                                      
4259         }                                                                                                
4260         return uniqueIntents;                                                                            
4261     }                                                                                                    
4262                                                                                                          
4263     void getUniqueIntents(CellLayout cl, ArrayList<ComponentName> uniqueIntents,                         
4264             ArrayList<ComponentName> duplicates, boolean stripDuplicates) {                              
4265         int count = cl.getShortcutsAndWidgets().getChildCount();                                         
4266                                                                                                          
4267         ArrayList<View> children = new ArrayList<View>();                                                
4268         for (int i = 0; i < count; i++) {                                                                
4269             View v = cl.getShortcutsAndWidgets().getChildAt(i);                                          
4270             children.add(v);                                                                             
4271         }                                                                                                
4272                                                                                                          
4273         for (int i = 0; i < count; i++) {                                                                
4274             View v = children.get(i);                                                                    
4275             ItemInfo info = (ItemInfo) v.getTag();                                                       
4276             // Null check required as the AllApps button doesn't have an item info                       
4277             if (info instanceof ShortcutInfo) {                                                          
4278                 ShortcutInfo si = (ShortcutInfo) info;                                                   
4279                 ComponentName cn = si.intent.getComponent();                                             
4280                                                                                                          
4281                 Uri dataUri = si.intent.getData();                                                       
4282                 // If dataUri is not null / empty or if this component isn't one that would              
4283                 // have previously showed up in the AllApps list, then this is a widget-type             
4284                 // shortcut, so ignore it.                                                               
4285                 if (dataUri != null && !dataUri.equals(Uri.EMPTY)) {                                     
4286                     continue;                                                                            
4287                 }                                                                                        
4288                                                                                                          
4289                 if (!uniqueIntents.contains(cn)) {                                                       
4290                     uniqueIntents.add(cn);                                                               
4291                 } else {                                                                                 
4292                     if (stripDuplicates) {                                                               
4293                         cl.removeViewInLayout(v);                                                        
4294                         LauncherModel.deleteItemFromDatabase(mLauncher, si);                             
4295                     }                                                                                    
4296                     if (duplicates != null) {                                                            
4297                         duplicates.add(cn);                                                              
4298                     }                                                                                    
4299                 }                                                                                        
4300             }                                                                                            
4301             if (v instanceof FolderIcon) {                                                               
4302                 FolderIcon fi = (FolderIcon) v;                                                          
4303                 ArrayList<View> items = fi.getFolder().getItemsInReadingOrder();                         
4304                 for (int j = 0; j < items.size(); j++) {                                                 
4305                     if (items.get(j).getTag() instanceof ShortcutInfo) {                                 
4306                         ShortcutInfo si = (ShortcutInfo) items.get(j).getTag();                          
4307                         ComponentName cn = si.intent.getComponent();                                     
4308                                                                                                          
4309                         Uri dataUri = si.intent.getData();                                               
4310                         // If dataUri is not null / empty or if this component isn't one that would      
4311                         // have previously showed up in the AllApps list, then this is a widget-type     
4312                         // shortcut, so ignore it.                                                       
4313                         if (dataUri != null && !dataUri.equals(Uri.EMPTY)) {                             
4314                             continue;                                                                    
4315                         }                                                                                
4316                                                                                                          
4317                         if (!uniqueIntents.contains(cn)) {                                               
4318                             uniqueIntents.add(cn);                                                       
4319                         }  else {                                                                        
4320                             if (stripDuplicates) {                                                       
4321                                 fi.getFolderInfo().remove(si);                                           
4322                                 LauncherModel.deleteItemFromDatabase(mLauncher, si);                     
4323                             }                                                                            
4324                             if (duplicates != null) {                                                    
4325                                 duplicates.add(cn);                                                      
4326                             }                                                                            
4327                         }                                                                                
4328                     }                                                                                    
4329                 }                                                                                        
4330             }                                                                                            
4331         }                                                                                                
4332     }                                                                                                    
4333                                                                                                          
4334     void saveWorkspaceToDb() {                                                                           
4335         saveWorkspaceScreenToDb((CellLayout) mLauncher.getHotseat().getLayout());                        
4336         int count = getChildCount();                                                                     
4337         for (int i = 0; i < count; i++) {                                                                
4338             CellLayout cl = (CellLayout) getChildAt(i);                                                  
4339             saveWorkspaceScreenToDb(cl);                                                                 
4340         }                                                                                                
4341     }                                                                                                    
4342                                                                                                          
4343     void saveWorkspaceScreenToDb(CellLayout cl) {                                                        
4344         int count = cl.getShortcutsAndWidgets().getChildCount();                                         
4345                                                                                                          
4346         long screenId = getIdForScreen(cl);                                                              
4347         int container = Favorites.CONTAINER_DESKTOP;                                                     
4348                                                                                                          
4349         Hotseat hotseat = mLauncher.getHotseat();                                                        
4350         if (mLauncher.isHotseatLayout(cl)) {                                                             
4351             screenId = -1;                                                                               
4352             container = Favorites.CONTAINER_HOTSEAT;                                                     
4353         }                                                                                                
4354                                                                                                          
4355         for (int i = 0; i < count; i++) {                                                                
4356             View v = cl.getShortcutsAndWidgets().getChildAt(i);                                          
4357             ItemInfo info = (ItemInfo) v.getTag();                                                       
4358             // Null check required as the AllApps button doesn't have an item info                       
4359             if (info != null) {                                                                          
4360                 int cellX = info.cellX;                                                                  
4361                 int cellY = info.cellY;                                                                  
4362                 if (container == Favorites.CONTAINER_HOTSEAT) {                                          
4363                     cellX = hotseat.getCellXFromOrder((int) info.screenId);                              
4364                     cellY = hotseat.getCellYFromOrder((int) info.screenId);                              
4365                 }                                                                                        
4366                 LauncherModel.addItemToDatabase(mLauncher, info, container, screenId, cellX,             
4367                         cellY, false);                                                                   
4368             }                                                                                            
4369             if (v instanceof FolderIcon) {                                                               
4370                 FolderIcon fi = (FolderIcon) v;                                                          
4371                 fi.getFolder().addItemLocationsInDatabase();                                             
4372             }                                                                                            
4373         }                                                                                                
4374     }                                                                                                    
4375                                                                                                          
4376     @Override                                                                                            
4377     public float getIntrinsicIconScaleFactor() {                                                         
4378         return 1f;                                                                                       
4379     }                                                                                                    
4380                                                                                                          
4381     @Override                                                                                            
4382     public boolean supportsFlingToDelete() {                                                             
4383         return true;                                                                                     
4384     }                                                                                                    
4385                                                                                                          
4386     @Override                                                                                            
4387     public boolean supportsAppInfoDropTarget() {                                                         
4388         return false;                                                                                    
4389     }                                                                                                    
4390                                                                                                          
4391     @Override                                                                                            
4392     public boolean supportsDeleteDropTarget() {                                                          
4393         return true;                                                                                     
4394     }                                                                                                    
4395                                                                                                          
4396     @Override                                                                                            
4397     public void onFlingToDelete(DragObject d, int x, int y, PointF vec) {                                
4398         // Do nothing                                                                                    
4399     }                                                                                                    
4400                                                                                                          
4401     @Override                                                                                            
4402     public void onFlingToDeleteCompleted() {                                                             
4403         // Do nothing                                                                                    
4404     }                                                                                                    
4405                                                                                                          
4406     public boolean isDropEnabled() {                                                                     
4407         return true;                                                                                     
4408     }                                                                                                    
4409                                                                                                          
4410     @Override                                                                                            
4411     protected void onRestoreInstanceState(Parcelable state) {                                            
4412         super.onRestoreInstanceState(state);                                                             
4413         Launcher.setScreen(mCurrentPage);                                                                
4414     }                                                                                                    
4415                                                                                                          
4416     @Override                                                                                            
4417     protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {                     
4418         // We don't dispatch restoreInstanceState to our children using this code path.                  
4419         // Some pages will be restored immediately as their items are bound immediately, and             
4420         // others we will need to wait until after their items are bound.                                
4421         mSavedStates = container;                                                                        
4422     }                                                                                                    
4423                                                                                                          
4424     public void restoreInstanceStateForChild(int child) {                                                
4425         if (mSavedStates != null) {                                                                      
4426             mRestoredPages.add(child);                                                                   
4427             CellLayout cl = (CellLayout) getChildAt(child);                                              
4428             if (cl != null) {                                                                            
4429                 cl.restoreInstanceState(mSavedStates);                                                   
4430             }                                                                                            
4431         }                                                                                                
4432     }                                                                                                    
4433                                                                                                          
4434     public void restoreInstanceStateForRemainingPages() {                                                
4435         int count = getChildCount();                                                                     
4436         for (int i = 0; i < count; i++) {                                                                
4437             if (!mRestoredPages.contains(i)) {                                                           
4438                 restoreInstanceStateForChild(i);                                                         
4439             }                                                                                            
4440         }                                                                                                
4441         mRestoredPages.clear();                                                                          
4442         mSavedStates = null;                                                                             
4443     }                                                                                                    
4444                                                                                                          
4445     @Override                                                                                            
4446     public void scrollLeft() {                                                                           
4447         if (!workspaceInModalState() && !mIsSwitchingState) {                                            
4448             super.scrollLeft();                                                                          
4449         }                                                                                                
4450         Folder openFolder = getOpenFolder();                                                             
4451         if (openFolder != null) {                                                                        
4452             openFolder.completeDragExit();                                                               
4453         }                                                                                                
4454     }                                                                                                    
4455                                                                                                          
4456     @Override                                                                                            
4457     public void scrollRight() {                                                                          
4458         if (!workspaceInModalState() && !mIsSwitchingState) {                                            
4459             super.scrollRight();                                                                         
4460         }                                                                                                
4461         Folder openFolder = getOpenFolder();                                                             
4462         if (openFolder != null) {                                                                        
4463             openFolder.completeDragExit();                                                               
4464         }                                                                                                
4465     }                                                                                                    
4466                                                                                                          
4467     @Override                                                                                            
4468     public boolean onEnterScrollArea(int x, int y, int direction) {                                      
4469         // Ignore the scroll area if we are dragging over the hot seat                                   
4470         boolean isPortrait = !LauncherAppState.isScreenLandscape(getContext());                          
4471         if (mLauncher.getHotseat() != null && isPortrait) {                                              
4472             Rect r = new Rect();                                                                         
4473             mLauncher.getHotseat().getHitRect(r);                                                        
4474             if (r.contains(x, y)) {                                                                      
4475                 return false;                                                                            
4476             }                                                                                            
4477         }                                                                                                
4478                                                                                                          
4479         boolean result = false;                                                                          
4480         if (!workspaceInModalState() && !mIsSwitchingState && getOpenFolder() == null) {                 
4481             mInScrollArea = true;                                                                        
4482                                                                                                          
4483             final int page = getNextPage() +                                                             
4484                        (direction == DragController.SCROLL_LEFT ? -1 : 1);                               
4485             // We always want to exit the current layout to ensure parity of enter / exit                
4486             setCurrentDropLayout(null);                                                                  
4487                                                                                                          
4488             if (0 <= page && page < getChildCount()) {                                                   
4489                 // Ensure that we are not dragging over to the custom content screen                     
4490                 if (getScreenIdForPageIndex(page) == CUSTOM_CONTENT_SCREEN_ID) {                         
4491                     return false;                                                                        
4492                 }                                                                                        
4493                                                                                                          
4494                 CellLayout layout = (CellLayout) getChildAt(page);                                       
4495                 setCurrentDragOverlappingLayout(layout);                                                 
4496                                                                                                          
4497                 // Workspace is responsible for drawing the edge glow on adjacent pages,                 
4498                 // so we need to redraw the workspace when this may have changed.                        
4499                 invalidate();                                                                            
4500                 result = true;                                                                           
4501             }                                                                                            
4502         }                                                                                                
4503         return result;                                                                                   
4504     }                                                                                                    
4505                                                                                                          
4506     @Override                                                                                            
4507     public boolean onExitScrollArea() {                                                                  
4508         boolean result = false;                                                                          
4509         if (mInScrollArea) {                                                                             
4510             invalidate();                                                                                
4511             CellLayout layout = getCurrentDropLayout();                                                  
4512             setCurrentDropLayout(layout);                                                                
4513             setCurrentDragOverlappingLayout(layout);                                                     
4514                                                                                                          
4515             result = true;                                                                               
4516             mInScrollArea = false;                                                                       
4517         }                                                                                                
4518         return result;                                                                                   
4519     }                                                                                                    
4520                                                                                                          
4521     private void onResetScrollArea() {                                                                   
4522         setCurrentDragOverlappingLayout(null);                                                           
4523         mInScrollArea = false;                                                                           
4524     }                                                                                                    
4525                                                                                                          
4526     /**                                                                                                  
4527      * Returns a specific CellLayout                                                                     
4528      */                                                                                                  
4529     CellLayout getParentCellLayoutForView(View v) {                                                      
4530         ArrayList<CellLayout> layouts = getWorkspaceAndHotseatCellLayouts();                             
4531         for (CellLayout layout : layouts) {                                                              
4532             if (layout.getShortcutsAndWidgets().indexOfChild(v) > -1) {                                  
4533                 return layout;                                                                           
4534             }                                                                                            
4535         }                                                                                                
4536         return null;                                                                                     
4537     }                                                                                                    
4538                                                                                                          
4539     /**                                                                                                  
4540      * Returns a list of all the CellLayouts in the workspace.                                           
4541      */                                                                                                  
4542     ArrayList<CellLayout> getWorkspaceAndHotseatCellLayouts() {                                          
4543         ArrayList<CellLayout> layouts = new ArrayList<CellLayout>();                                     
4544         int screenCount = getChildCount();                                                               
4545         for (int screen = 0; screen < screenCount; screen++) {                                           
4546             layouts.add(((CellLayout) getChildAt(screen)));                                              
4547         }                                                                                                
4548         if (mLauncher.getHotseat() != null) {                                                            
4549             layouts.add(mLauncher.getHotseat().getLayout());                                             
4550         }                                                                                                
4551         return layouts;                                                                                  
4552     }                                                                                                    
4553                                                                                                          
4554     /**                                                                                                  
4555      * We should only use this to search for specific children.  Do not use this method to modify        
4556      * ShortcutsAndWidgetsContainer directly. Includes ShortcutAndWidgetContainers from                  
4557      * the hotseat and workspace pages                                                                   
4558      */                                                                                                  
4559     ArrayList<ShortcutAndWidgetContainer> getAllShortcutAndWidgetContainers() {                          
4560         ArrayList<ShortcutAndWidgetContainer> childrenLayouts =                                          
4561                 new ArrayList<ShortcutAndWidgetContainer>();                                             
4562         int screenCount = getChildCount();                                                               
4563         for (int screen = 0; screen < screenCount; screen++) {                                           
4564             childrenLayouts.add(((CellLayout) getChildAt(screen)).getShortcutsAndWidgets());             
4565         }                                                                                                
4566         if (mLauncher.getHotseat() != null) {                                                            
4567             childrenLayouts.add(mLauncher.getHotseat().getLayout().getShortcutsAndWidgets());            
4568         }                                                                                                
4569         return childrenLayouts;                                                                          
4570     }                                                                                                    
4571                                                                                                          
4572     public Folder getFolderForTag(final Object tag) {                                                    
4573         return (Folder) getFirstMatch(new ItemOperator() {                                               
4574                                                                                                          
4575             @Override                                                                                    
4576             public boolean evaluate(ItemInfo info, View v, View parent) {                                
4577                 return (v instanceof Folder) && (((Folder) v).getInfo() == tag)                          
4578                         && ((Folder) v).getInfo().opened;                                                
4579             }                                                                                            
4580         });                                                                                              
4581     }                                                                                                    
4582                                                                                                          
4583     public View getViewForTag(final Object tag) {                                                        
4584         return getFirstMatch(new ItemOperator() {                                                        
4585                                                                                                          
4586             @Override                                                                                    
4587             public boolean evaluate(ItemInfo info, View v, View parent) {                                
4588                 return info == tag;                                                                      
4589             }                                                                                            
4590         });                                                                                              
4591     }                                                                                                    
4592                                                                                                          
4593     public LauncherAppWidgetHostView getWidgetForAppWidgetId(final int appWidgetId) {                    
4594         return (LauncherAppWidgetHostView) getFirstMatch(new ItemOperator() {                            
4595                                                                                                          
4596             @Override                                                                                    
4597             public boolean evaluate(ItemInfo info, View v, View parent) {                                
4598                 return (info instanceof LauncherAppWidgetInfo) &&                                        
4599                         ((LauncherAppWidgetInfo) info).appWidgetId == appWidgetId;                       
4600             }                                                                                            
4601         });                                                                                              
4602     }                                                                                                    
4603                                                                                                          
4604     private View getFirstMatch(final ItemOperator operator) {                                            
4605         final View[] value = new View[1];                                                                
4606         mapOverItems(MAP_NO_RECURSE, new ItemOperator() {                                                
4607             @Override                                                                                    
4608             public boolean evaluate(ItemInfo info, View v, View parent) {                                
4609                 if (operator.evaluate(info, v, parent)) {                                                
4610                     value[0] = v;                                                                        
4611                     return true;                                                                         
4612                 }                                                                                        
4613                 return false;                                                                            
4614             }                                                                                            
4615         });                                                                                              
4616         return value[0];                                                                                 
4617     }                                                                                                    
4618                                                                                                          
4619     void clearDropTargets() {                                                                            
4620         mapOverItems(MAP_NO_RECURSE, new ItemOperator() {                                                
4621             @Override                                                                                    
4622             public boolean evaluate(ItemInfo info, View v, View parent) {                                
4623                 if (v instanceof DropTarget) {                                                           
4624                     mDragController.removeDropTarget((DropTarget) v);                                    
4625                 }                                                                                        
4626                 // not done, process all the shortcuts                                                   
4627                 return false;                                                                            
4628             }                                                                                            
4629         });                                                                                              
4630     }                                                                                                    
4631                                                                                                          
4632     // Removes ALL items that match a given package name, this is usually called when a package          
4633     // has been removed and we want to remove all components (widgets, shortcuts, apps) that             
4634     // belong to that package.                                                                           
4635     void removeItemsByPackageName(final ArrayList<String> packages, final UserHandleCompat user) {       
4636         final HashSet<String> packageNames = new HashSet<String>();                                      
4637         packageNames.addAll(packages);                                                                   
4638                                                                                                          
4639         // Filter out all the ItemInfos that this is going to affect                                     
4640         final HashSet<ItemInfo> infos = new HashSet<ItemInfo>();                                         
4641         final HashSet<ComponentName> cns = new HashSet<ComponentName>();                                 
4642         ArrayList<CellLayout> cellLayouts = getWorkspaceAndHotseatCellLayouts();                         
4643         for (CellLayout layoutParent : cellLayouts) {                                                    
4644             ViewGroup layout = layoutParent.getShortcutsAndWidgets();                                    
4645             int childCount = layout.getChildCount();                                                     
4646             for (int i = 0; i < childCount; ++i) {                                                       
4647                 View view = layout.getChildAt(i);                                                        
4648                 infos.add((ItemInfo) view.getTag());                                                     
4649             }                                                                                            
4650         }                                                                                                
4651         LauncherModel.ItemInfoFilter filter = new LauncherModel.ItemInfoFilter() {                       
4652             @Override                                                                                    
4653             public boolean filterItem(ItemInfo parent, ItemInfo info,                                    
4654                                       ComponentName cn) {                                                
4655                 if (packageNames.contains(cn.getPackageName())                                           
4656                         && info.user.equals(user)) {                                                     
4657                     cns.add(cn);                                                                         
4658                     return true;                                                                         
4659                 }                                                                                        
4660                 return false;                                                                            
4661             }                                                                                            
4662         };                                                                                               
4663         LauncherModel.filterItemInfos(infos, filter);                                                    
4664                                                                                                          
4665         // Remove the affected components                                                                
4666         removeItemsByComponentName(cns, user);                                                           
4667     }                                                                                                    
4668                                                                                                          
4669     // Removes items that match the application info specified, when applications are removed            
4670     // as a part of an update, this is called to ensure that other widgets and application               
4671     // shortcuts are not removed.                                                                        
4672     void removeItemsByApplicationInfo(final ArrayList<AppInfo> appInfos, UserHandleCompat user) {        
4673         // Just create a hash table of all the specific components that this will affect                 
4674         HashSet<ComponentName> cns = new HashSet<ComponentName>();                                       
4675         for (AppInfo info : appInfos) {                                                                  
4676             cns.add(info.componentName);                                                                 
4677         }                                                                                                
4678                                                                                                          
4679         // Remove all the things                                                                         
4680         removeItemsByComponentName(cns, user);                                                           
4681     }                                                                                                    
4682                                                                                                          
4683     void removeItemsByComponentName(final HashSet<ComponentName> componentNames,                         
4684             final UserHandleCompat user) {                                                               
4685         ArrayList<CellLayout> cellLayouts = getWorkspaceAndHotseatCellLayouts();                         
4686         for (final CellLayout layoutParent: cellLayouts) {                                               
4687             final ViewGroup layout = layoutParent.getShortcutsAndWidgets();                              
4688                                                                                                          
4689             final HashMap<ItemInfo, View> children = new HashMap<ItemInfo, View>();                      
4690             for (int j = 0; j < layout.getChildCount(); j++) {                                           
4691                 final View view = layout.getChildAt(j);                                                  
4692                 children.put((ItemInfo) view.getTag(), view);                                            
4693             }                                                                                            
4694                                                                                                          
4695             final ArrayList<View> childrenToRemove = new ArrayList<View>();                              
4696             final HashMap<FolderInfo, ArrayList<ShortcutInfo>> folderAppsToRemove =                      
4697                     new HashMap<FolderInfo, ArrayList<ShortcutInfo>>();                                  
4698             LauncherModel.ItemInfoFilter filter = new LauncherModel.ItemInfoFilter() {                   
4699                 @Override                                                                                
4700                 public boolean filterItem(ItemInfo parent, ItemInfo info,                                
4701                                           ComponentName cn) {                                            
4702                     if (parent instanceof FolderInfo) {                                                  
4703                         if (componentNames.contains(cn) && info.user.equals(user)) {                     
4704                             FolderInfo folder = (FolderInfo) parent;                                     
4705                             ArrayList<ShortcutInfo> appsToRemove;                                        
4706                             if (folderAppsToRemove.containsKey(folder)) {                                
4707                                 appsToRemove = folderAppsToRemove.get(folder);                           
4708                             } else {                                                                     
4709                                 appsToRemove = new ArrayList<ShortcutInfo>();                            
4710                                 folderAppsToRemove.put(folder, appsToRemove);                            
4711                             }                                                                            
4712                             appsToRemove.add((ShortcutInfo) info);                                       
4713                             return true;                                                                 
4714                         }                                                                                
4715                     } else {                                                                             
4716                         if (componentNames.contains(cn) && info.user.equals(user)) {                     
4717                             childrenToRemove.add(children.get(info));                                    
4718                             return true;                                                                 
4719                         }                                                                                
4720                     }                                                                                    
4721                     return false;                                                                        
4722                 }                                                                                        
4723             };                                                                                           
4724             LauncherModel.filterItemInfos(children.keySet(), filter);                                    
4725                                                                                                          
4726             // Remove all the apps from their folders                                                    
4727             for (FolderInfo folder : folderAppsToRemove.keySet()) {                                      
4728                 ArrayList<ShortcutInfo> appsToRemove = folderAppsToRemove.get(folder);                   
4729                 for (ShortcutInfo info : appsToRemove) {                                                 
4730                     folder.remove(info);                                                                 
4731                 }                                                                                        
4732             }                                                                                            
4733                                                                                                          
4734             // Remove all the other children                                                             
4735             for (View child : childrenToRemove) {                                                        
4736                 // Note: We can not remove the view directly from CellLayoutChildren as this             
4737                 // does not re-mark the spaces as unoccupied.                                            
4738                 layoutParent.removeViewInLayout(child);                                                  
4739                 if (child instanceof DropTarget) {                                                       
4740                     mDragController.removeDropTarget((DropTarget) child);                                
4741                 }                                                                                        
4742             }                                                                                            
4743                                                                                                          
4744             if (childrenToRemove.size() > 0) {                                                           
4745                 layout.requestLayout();                                                                  
4746                 layout.invalidate();                                                                     
4747             }                                                                                            
4748         }                                                                                                
4749                                                                                                          
4750         // Strip all the empty screens                                                                   
4751         stripEmptyScreens();                                                                             
4752     }                                                                                                    
4753                                                                                                          
4754     interface ItemOperator {                                                                             
4755         /**                                                                                              
4756          * Process the next itemInfo, possibly with side-effect on {@link ItemOperator#value}.           
4757          *                                                                                               
4758          * @param info info for the shortcut                                                             
4759          * @param view view for the shortcut                                                             
4760          * @param parent containing folder, or null                                                      
4761          * @return true if done, false to continue the map                                               
4762          */                                                                                              
4763         public boolean evaluate(ItemInfo info, View view, View parent);                                  
4764     }                                                                                                    
4765                                                                                                          
4766     /**                                                                                                  
4767      * Map the operator over the shortcuts and widgets, return the first-non-null value.                 
4768      *                                                                                                   
4769      * @param recurse true: iterate over folder children. false: op get the folders themselves.          
4770      * @param op the operator to map over the shortcuts                                                  
4771      */                                                                                                  
4772     void mapOverItems(boolean recurse, ItemOperator op) {                                                
4773         ArrayList<ShortcutAndWidgetContainer> containers = getAllShortcutAndWidgetContainers();          
4774         final int containerCount = containers.size();                                                    
4775         for (int containerIdx = 0; containerIdx < containerCount; containerIdx++) {                      
4776             ShortcutAndWidgetContainer container = containers.get(containerIdx);                         
4777             // map over all the shortcuts on the workspace                                               
4778             final int itemCount = container.getChildCount();                                             
4779             for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) {                                      
4780                 View item = container.getChildAt(itemIdx);                                               
4781                 ItemInfo info = (ItemInfo) item.getTag();                                                
4782                 if (recurse && info instanceof FolderInfo && item instanceof FolderIcon) {               
4783                     FolderIcon folder = (FolderIcon) item;                                               
4784                     ArrayList<View> folderChildren = folder.getFolder().getItemsInReadingOrder();        
4785                     // map over all the children in the folder                                           
4786                     final int childCount = folderChildren.size();                                        
4787                     for (int childIdx = 0; childIdx < childCount; childIdx++) {                          
4788                         View child = folderChildren.get(childIdx);                                       
4789                         info = (ItemInfo) child.getTag();                                                
4790                         if (op.evaluate(info, child, folder)) {                                          
4791                             return;                                                                      
4792                         }                                                                                
4793                     }                                                                                    
4794                 } else {                                                                                 
4795                     if (op.evaluate(info, item, null)) {                                                 
4796                         return;                                                                          
4797                     }                                                                                    
4798                 }                                                                                        
4799             }                                                                                            
4800         }                                                                                                
4801     }                                                                                                    
4802                                                                                                          
4803     void updateShortcutsAndWidgets(ArrayList<AppInfo> apps) {                                            
4804         // Break the appinfo list per user                                                               
4805         final HashMap<UserHandleCompat, ArrayList<AppInfo>> appsPerUser =                                
4806                 new HashMap<UserHandleCompat, ArrayList<AppInfo>>();                                     
4807         for (AppInfo info : apps) {                                                                      
4808             ArrayList<AppInfo> filtered = appsPerUser.get(info.user);                                    
4809             if (filtered == null) {                                                                      
4810                 filtered = new ArrayList<AppInfo>();                                                     
4811                 appsPerUser.put(info.user, filtered);                                                    
4812             }                                                                                            
4813             filtered.add(info);                                                                          
4814         }                                                                                                
4815                                                                                                          
4816         for (Map.Entry<UserHandleCompat, ArrayList<AppInfo>> entry : appsPerUser.entrySet()) {           
4817             updateShortcutsAndWidgetsPerUser(entry.getValue(), entry.getKey());                          
4818         }                                                                                                
4819     }                                                                                                    
4820                                                                                                          
4821     private void updateShortcutsAndWidgetsPerUser(ArrayList<AppInfo> apps,                               
4822             final UserHandleCompat user) {                                                               
4823         // Create a map of the apps to test against                                                      
4824         final HashMap<ComponentName, AppInfo> appsMap = new HashMap<ComponentName, AppInfo>();           
4825         final HashSet<String> pkgNames = new HashSet<String>();                                          
4826         for (AppInfo ai : apps) {                                                                        
4827             appsMap.put(ai.componentName, ai);                                                           
4828             pkgNames.add(ai.componentName.getPackageName());                                             
4829         }                                                                                                
4830         final HashSet<ComponentName> iconsToRemove = new HashSet<ComponentName>();                       
4831                                                                                                          
4832         mapOverItems(MAP_RECURSE, new ItemOperator() {                                                   
4833             @Override                                                                                    
4834             public boolean evaluate(ItemInfo info, View v, View parent) {                                
4835                 if (info instanceof ShortcutInfo && v instanceof BubbleTextView) {                       
4836                     ShortcutInfo shortcutInfo = (ShortcutInfo) info;                                     
4837                     ComponentName cn = shortcutInfo.getTargetComponent();                                
4838                     AppInfo appInfo = appsMap.get(cn);                                                   
4839                     if (user.equals(shortcutInfo.user) && cn != null                                     
4840                             && LauncherModel.isShortcutInfoUpdateable(info)                              
4841                             && pkgNames.contains(cn.getPackageName())) {                                 
4842                         boolean promiseStateChanged = false;                                             
4843                         boolean infoUpdated = false;                                                     
4844                         if (shortcutInfo.isPromise()) {                                                  
4845                             if (shortcutInfo.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {         
4846                                 // Auto install icon                                                     
4847                                 PackageManager pm = getContext().getPackageManager();                    
4848                                 ResolveInfo matched = pm.resolveActivity(                                
4849                                         new Intent(Intent.ACTION_MAIN)                                   
4850                                         .setComponent(cn).addCategory(Intent.CATEGORY_LAUNCHER),         
4851                                         PackageManager.MATCH_DEFAULT_ONLY);                              
4852                                 if (matched == null) {                                                   
4853                                     // Try to find the best match activity.                              
4854                                     Intent intent = pm.getLaunchIntentForPackage(                        
4855                                             cn.getPackageName());                                        
4856                                     if (intent != null) {                                                
4857                                         cn = intent.getComponent();                                      
4858                                         appInfo = appsMap.get(cn);                                       
4859                                     }                                                                    
4860                                                                                                          
4861                                     if ((intent == null) || (appsMap == null)) {                         
4862                                         // Could not find a default activity. Remove this item.          
4863                                         iconsToRemove.add(shortcutInfo.getTargetComponent());            
4864                                                                                                          
4865                                         // process next shortcut.                                        
4866                                         return false;                                                    
4867                                     }                                                                    
4868                                     shortcutInfo.promisedIntent = intent;                                
4869                                 }                                                                        
4870                             }                                                                            
4871                                                                                                          
4872                             // Restore the shortcut.                                                     
4873                             shortcutInfo.intent = shortcutInfo.promisedIntent;                           
4874                             shortcutInfo.promisedIntent = null;                                          
4875                             shortcutInfo.status &= ~ShortcutInfo.FLAG_RESTORED_ICON                      
4876                                     & ~ShortcutInfo.FLAG_AUTOINTALL_ICON                                 
4877                                     & ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;                         
4878                                                                                                          
4879                             promiseStateChanged = true;                                                  
4880                             infoUpdated = true;                                                          
4881                             shortcutInfo.updateIcon(mIconCache);                                         
4882                             LauncherModel.updateItemInDatabase(getContext(), shortcutInfo);              
4883                         }                                                                                
4884                                                                                                          
4885                                                                                                          
4886                         if (appInfo != null) {                                                           
4887                             shortcutInfo.updateIcon(mIconCache);                                         
4888                             shortcutInfo.title = appInfo.title.toString();                               
4889                             shortcutInfo.contentDescription = appInfo.contentDescription;                
4890                             infoUpdated = true;                                                          
4891                         }                                                                                
4892                                                                                                          
4893                         if (infoUpdated) {                                                               
4894                             BubbleTextView shortcut = (BubbleTextView) v;                                
4895                             shortcut.applyFromShortcutInfo(shortcutInfo,                                 
4896                                     mIconCache, true, promiseStateChanged);                              
4897                                                                                                          
4898                             if (parent != null) {                                                        
4899                                 parent.invalidate();                                                     
4900                             }                                                                            
4901                         }                                                                                
4902                     }                                                                                    
4903                 }                                                                                        
4904                 // process all the shortcuts                                                             
4905                 return false;                                                                            
4906             }                                                                                            
4907         });                                                                                              
4908                                                                                                          
4909         if (!iconsToRemove.isEmpty()) {                                                                  
4910             removeItemsByComponentName(iconsToRemove, user);                                             
4911         }                                                                                                
4912         if (user.equals(UserHandleCompat.myUserHandle())) {                                              
4913             restorePendingWidgets(pkgNames);                                                             
4914         }                                                                                                
4915     }                                                                                                    
4916                                                                                                          
4917     public void removeAbandonedPromise(String packageName, UserHandleCompat user) {                      
4918         ArrayList<String> packages = new ArrayList<String>(1);                                           
4919         packages.add(packageName);                                                                       
4920         LauncherModel.deletePackageFromDatabase(mLauncher, packageName, user);                           
4921         removeItemsByPackageName(packages, user);                                                        
4922     }                                                                                                    
4923                                                                                                          
4924     public void updatePackageBadge(final String packageName, final UserHandleCompat user) {              
4925         mapOverItems(MAP_RECURSE, new ItemOperator() {                                                   
4926             @Override                                                                                    
4927             public boolean evaluate(ItemInfo info, View v, View parent) {                                
4928                 if (info instanceof ShortcutInfo && v instanceof BubbleTextView) {                       
4929                     ShortcutInfo shortcutInfo = (ShortcutInfo) info;                                     
4930                     ComponentName cn = shortcutInfo.getTargetComponent();                                
4931                     if (user.equals(shortcutInfo.user) && cn != null                                     
4932                             && shortcutInfo.isPromise()                                                  
4933                             && packageName.equals(cn.getPackageName())) {                                
4934                         if (shortcutInfo.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {             
4935                             // For auto install apps update the icon as well as label.                   
4936                             mIconCache.getTitleAndIcon(shortcutInfo,                                     
4937                                     shortcutInfo.promisedIntent, user, true);                            
4938                         } else {                                                                         
4939                             // Only update the icon for restored apps.                                   
4940                             shortcutInfo.updateIcon(mIconCache);                                         
4941                         }                                                                                
4942                         BubbleTextView shortcut = (BubbleTextView) v;                                    
4943                         shortcut.applyFromShortcutInfo(shortcutInfo, mIconCache, true, false);           
4944                                                                                                          
4945                         if (parent != null) {                                                            
4946                             parent.invalidate();                                                         
4947                         }                                                                                
4948                     }                                                                                    
4949                 }                                                                                        
4950                 // process all the shortcuts                                                             
4951                 return false;                                                                            
4952             }                                                                                            
4953         });                                                                                              
4954     }                                                                                                    
4955                                                                                                          
4956     public void updatePackageState(ArrayList<PackageInstallInfo> installInfos) {                         
4957         HashSet<String> completedPackages = new HashSet<String>();                                       
4958                                                                                                          
4959         for (final PackageInstallInfo installInfo : installInfos) {                                      
4960             mapOverItems(MAP_RECURSE, new ItemOperator() {                                               
4961                 @Override                                                                                
4962                 public boolean evaluate(ItemInfo info, View v, View parent) {                            
4963                     if (info instanceof ShortcutInfo && v instanceof BubbleTextView) {                   
4964                         ShortcutInfo si = (ShortcutInfo) info;                                           
4965                         ComponentName cn = si.getTargetComponent();                                      
4966                         if (si.isPromise() && (cn != null)                                               
4967                                 && installInfo.packageName.equals(cn.getPackageName())) {                
4968                             si.setInstallProgress(installInfo.progress);                                 
4969                             if (installInfo.state == PackageInstallerCompat.STATUS_FAILED) {             
4970                                 // Mark this info as broken.                                             
4971                                 si.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;                  
4972                             }                                                                            
4973                             ((BubbleTextView)v).applyState(false);                                       
4974                         }                                                                                
4975                     } else if (v instanceof PendingAppWidgetHostView                                     
4976                             && info instanceof LauncherAppWidgetInfo                                     
4977                             && ((LauncherAppWidgetInfo) info).providerName.getPackageName()              
4978                                 .equals(installInfo.packageName)) {                                      
4979                         ((LauncherAppWidgetInfo) info).installProgress = installInfo.progress;           
4980                         ((PendingAppWidgetHostView) v).applyState();                                     
4981                     }                                                                                    
4982                                                                                                          
4983                     // process all the shortcuts                                                         
4984                     return false;                                                                        
4985                 }                                                                                        
4986             });                                                                                          
4987                                                                                                          
4988             if (installInfo.state == PackageInstallerCompat.STATUS_INSTALLED) {                          
4989                 completedPackages.add(installInfo.packageName);                                          
4990             }                                                                                            
4991         }                                                                                                
4992                                                                                                          
4993         // Note that package states are sent only for myUser                                             
4994         if (!completedPackages.isEmpty()) {                                                              
4995             restorePendingWidgets(completedPackages);                                                    
4996         }                                                                                                
4997     }                                                                                                    
4998                                                                                                          
4999     private void restorePendingWidgets(final Set<String> installedPackaged) {                            
5000         final ArrayList<LauncherAppWidgetInfo> changedInfo = new ArrayList<LauncherAppWidgetInfo>();     
5001                                                                                                          
5002         // Iterate non recursively as widgets can't be inside a folder.                                  
5003         mapOverItems(MAP_NO_RECURSE, new ItemOperator() {                                                
5004                                                                                                          
5005             @Override                                                                                    
5006             public boolean evaluate(ItemInfo info, View v, View parent) {                                
5007                 if (info instanceof LauncherAppWidgetInfo) {                                             
5008                     LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info;                     
5009                     if (widgetInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)         
5010                             && installedPackaged.contains(widgetInfo.providerName.getPackageName())) {   
5011                                                                                                          
5012                         changedInfo.add(widgetInfo);                                                     
5013                                                                                                          
5014                         // Remove the provider not ready flag                                            
5015                         widgetInfo.restoreStatus &= ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;      
5016                         LauncherModel.updateItemInDatabase(getContext(), widgetInfo);                    
5017                     }                                                                                    
5018                 }                                                                                        
5019                 // process all the widget                                                                
5020                 return false;                                                                            
5021             }                                                                                            
5022         });                                                                                              
5023         if (!changedInfo.isEmpty()) {                                                                    
5024             DeferredWidgetRefresh widgetRefresh = new DeferredWidgetRefresh(changedInfo,                 
5025                     mLauncher.getAppWidgetHost());                                                       
5026             if (LauncherModel.findAppWidgetProviderInfoWithComponent(getContext(),                       
5027                     changedInfo.get(0).providerName) != null) {                                          
5028                 // Re-inflate the widgets which have changed status                                      
5029                 widgetRefresh.run();                                                                     
5030             } else {                                                                                     
5031                 // widgetRefresh will automatically run when the packages are updated.                   
5032             }                                                                                            
5033         }                                                                                                
5034     }                                                                                                    
5035                                                                                                          
5036     private void moveToScreen(int page, boolean animate) {                                               
5037         if (!workspaceInModalState()) {                                                                  
5038             if (animate) {                                                                               
5039                 snapToPage(page);                                                                        
5040             } else {                                                                                     
5041                 setCurrentPage(page);                                                                    
5042             }                                                                                            
5043         }                                                                                                
5044         View child = getChildAt(page);                                                                   
5045         if (child != null) {                                                                             
5046             child.requestFocus();                                                                        
5047         }                                                                                                
5048     }                                                                                                    
5049                                                                                                          
5050     void moveToDefaultScreen(boolean animate) {                                                          
5051         moveToScreen(mDefaultPage, animate);                                                             
5052     }                                                                                                    
5053                                                                                                          
5054     void moveToCustomContentScreen(boolean animate) {                                                    
5055         if (hasCustomContent()) {                                                                        
5056             int ccIndex = getPageIndexForScreenId(CUSTOM_CONTENT_SCREEN_ID);                             
5057             if (animate) {                                                                               
5058                 snapToPage(ccIndex);                                                                     
5059             } else {                                                                                     
5060                 setCurrentPage(ccIndex);                                                                 
5061             }                                                                                            
5062             View child = getChildAt(ccIndex);                                                            
5063             if (child != null) {                                                                         
5064                 child.requestFocus();                                                                    
5065             }                                                                                            
5066          }                                                                                               
5067         exitWidgetResizeMode();                                                                          
5068     }                                                                                                    
5069                                                                                                          
5070     @Override                                                                                            
5071     protected PageIndicator.PageMarkerResources getPageIndicatorMarker(int pageIndex) {                  
5072         long screenId = getScreenIdForPageIndex(pageIndex);                                              
5073         if (screenId == EXTRA_EMPTY_SCREEN_ID) {                                                         
5074             int count = mScreenOrder.size() - numCustomPages();                                          
5075             if (count > 1) {                                                                             
5076                 return new PageIndicator.PageMarkerResources(R.drawable.ic_pageindicator_current,        
5077                         R.drawable.ic_pageindicator_add);                                                
5078             }                                                                                            
5079         }                                                                                                
5080                                                                                                          
5081         return super.getPageIndicatorMarker(pageIndex);                                                  
5082     }                                                                                                    
5083                                                                                                          
5084     @Override                                                                                            
5085     public void syncPages() {                                                                            
5086     }                                                                                                    
5087                                                                                                          
5088     @Override                                                                                            
5089     public void syncPageItems(int page, boolean immediate) {                                             
5090     }                                                                                                    
5091                                                                                                          
5092     protected String getPageIndicatorDescription() {                                                     
5093         String settings = getResources().getString(R.string.settings_button_text);                       
5094         return getCurrentPageDescription() + ", " + settings;                                            
5095     }                                                                                                    
5096                                                                                                          
5097     protected String getCurrentPageDescription() {                                                       
5098         int page = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage;                               
5099         int delta = numCustomPages();                                                                    
5100         if (hasCustomContent() && getNextPage() == 0) {                                                  
5101             return mCustomContentDescription;                                                            
5102         }                                                                                                
5103         return String.format(getContext().getString(R.string.workspace_scroll_format),                   
5104                 page + 1 - delta, getChildCount() - delta);                                              
5105     }                                                                                                    
5106                                                                                                          
5107     public void getLocationInDragLayer(int[] loc) {                                                      
5108         mLauncher.getDragLayer().getLocationInDragLayer(this, loc);                                      
5109     }                                                                                                    
5110                                                                                                          
5111     /**                                                                                                  
5112      * Used as a workaround to ensure that the AppWidgetService receives the                             
5113      * PACKAGE_ADDED broadcast before updating widgets.                                                  
5114      */                                                                                                  
5115     private class DeferredWidgetRefresh implements Runnable {                                            
5116         private final ArrayList<LauncherAppWidgetInfo> mInfos;                                           
5117         private final LauncherAppWidgetHost mHost;                                                       
5118         private final Handler mHandler;                                                                  
5119                                                                                                          
5120         private boolean mRefreshPending;                                                                 
5121                                                                                                          
5122         public DeferredWidgetRefresh(ArrayList<LauncherAppWidgetInfo> infos,                             
5123                 LauncherAppWidgetHost host) {                                                            
5124             mInfos = infos;                                                                              
5125             mHost = host;                                                                                
5126             mHandler = new Handler();                                                                    
5127             mRefreshPending = true;                                                                      
5128                                                                                                          
5129             mHost.addProviderChangeListener(this);                                                       
5130             // Force refresh after 10 seconds, if we don't get the provider changed event.               
5131             // This could happen when the provider is no longer available in the app.                    
5132             mHandler.postDelayed(this, 10000);                                                           
5133         }                                                                                                
5134                                                                                                          
5135         @Override                                                                                        
5136         public void run() {                                                                              
5137             mHost.removeProviderChangeListener(this);                                                    
5138             mHandler.removeCallbacks(this);                                                              
5139                                                                                                          
5140             if (!mRefreshPending) {                                                                      
5141                 return;                                                                                  
5142             }                                                                                            
5143                                                                                                          
5144             mRefreshPending = false;                                                                     
5145                                                                                                          
5146             for (LauncherAppWidgetInfo info : mInfos) {                                                  
5147                 if (info.hostView instanceof PendingAppWidgetHostView) {                                 
5148                     PendingAppWidgetHostView view = (PendingAppWidgetHostView) info.hostView;            
5149                     mLauncher.removeAppWidget(info);                                                     
5150                                                                                                          
5151                     CellLayout cl = (CellLayout) view.getParent().getParent();                           
5152                     // Remove the current widget                                                         
5153                     cl.removeView(view);                                                                 
5154                     mLauncher.bindAppWidget(info);                                                       
5155                 }                                                                                        
5156             }                                                                                            
5157         }                                                                                                
5158     }                                                                                                    
5159 }                                                                                                        










































































































































   1 /*                                                                                                       
   2  * Copyright (C) 2008 The Android Open Source Project                                                    
   3  *                                                                                                       
   4  * Licensed under the Apache License, Version 2.0 (the "License");                                       
   5  * you may not use this file except in compliance with the License.                                      
   6  * You may obtain a copy of the License at                                                               
   7  *                                                                                                       
   8  *      http://www.apache.org/licenses/LICENSE-2.0                                                       
   9  *                                                                                                       
  10  * Unless required by applicable law or agreed to in writing, software                                   
  11  * distributed under the License is distributed on an "AS IS" BASIS,                                     
  12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.                              
  13  * See the License for the specific language governing permissions and                                   
  14  * limitations under the License.                                                                        
  15  */                                                                                                      
  16 package com.android.launcher3;                                                                           
  17                                                                                                          
  18 import android.animation.Animator.AnimatorListener;                                                      
  19 import android.animation.Animator;                                                                       
  20 import android.animation.AnimatorListenerAdapter;                                                        
  21 import android.animation.AnimatorSet;                                                                    
  22 import android.animation.LayoutTransition;                                                               
  23 import android.animation.ObjectAnimator;                                                                 
  24 import android.animation.PropertyValuesHolder;                                                           
  25 import android.animation.TimeInterpolator;                                                               
  26 import android.animation.ValueAnimator.AnimatorUpdateListener;                                           
  27 import android.animation.ValueAnimator;                                                                  
  28 import android.app.WallpaperManager;                                                                     
  29 import android.appwidget.AppWidgetHostView;                                                              
  30 import android.appwidget.AppWidgetProviderInfo;                                                          
  31 import android.content.ComponentName;                                                                    
  32 import android.content.Context;                                                                          
  33 import android.content.Intent;                                                                           
  34 import android.content.SharedPreferences;                                                                
  35 import android.content.pm.PackageManager;                                                                
  36 import android.content.pm.ResolveInfo;                                                                   
  37 import android.content.res.Resources;                                                                    
  38 import android.content.res.TypedArray;                                                                   
  39 import android.graphics.Bitmap;                                                                          
  40 import android.graphics.Canvas;                                                                          
  41 import android.graphics.Matrix;                                                                          
  42 import android.graphics.Paint;                                                                           
  43 import android.graphics.Point;                                                                           
  44 import android.graphics.PointF;                                                                          
  45 import android.graphics.Rect;                                                                            
  46 import android.graphics.Region.Op;                                                                       
  47 import android.graphics.drawable.Drawable;                                                               
  48 import android.net.Uri;                                                                                  
  49 import android.os.AsyncTask;                                                                             
  50 import android.os.Handler;                                                                               
  51 import android.os.IBinder;                                                                               
  52 import android.os.Parcelable;                                                                            
  53 import android.support.v4.view.ViewCompat;                                                               
  54 import android.util.AttributeSet;                                                                        
  55 import android.util.Log;                                                                                 
  56 import android.util.SparseArray;                                                                         
  57 import android.view.Choreographer;                                                                       
  58 import android.view.Display;                                                                             
  59 import android.view.MotionEvent;                                                                         
  60 import android.view.View;                                                                                
  61 import android.view.ViewGroup;                                                                           
  62 import android.view.accessibility.AccessibilityManager;                                                  
  63 import android.view.animation.DecelerateInterpolator;                                                    
  64 import android.view.animation.Interpolator;                                                              
  65 import android.widget.TextView;                                                                          
  66 import com.android.launcher3.FolderIcon.FolderRingAnimator;                                              
  67 import com.android.launcher3.Launcher.CustomContentCallbacks;                                            
  68 import com.android.launcher3.LauncherSettings.Favorites;                                                 
  69 import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;                           
  70 import com.android.launcher3.compat.PackageInstallerCompat;                                              
  71 import com.android.launcher3.compat.UserHandleCompat;                                                    
  72 import java.util.ArrayList;                                                                              
  73 import java.util.HashMap;                                                                                
  74 import java.util.HashSet;                                                                                
  75 import java.util.Iterator;                                                                               
  76 import java.util.Map;                                                                                    
  77 import java.util.Set;                                                                                    
  78 import java.util.concurrent.atomic.AtomicInteger;                                                        
  79                                                                                                          
  80                                                                                                          
  81 /**                                                                                                      
  82  * The workspace is a wide area with a wallpaper and a finite number of pages.                           
  83  * Each page contains a number of icons, folders or widgets the user can                                 
  84  * interact with. A workspace is meant to be used with a fixed width only.                               
  85  */                                                                                                      
  86 public class Workspace extends SmoothPagedView implements DropTarget , DragSource , DragScroller , View.O🔵
  87     private static final String TAG = "Launcher.Workspace";                                              
  88                                                                                                          
  89     // Y rotation to apply to the workspace screens                                                      
  90     // Y rotation to apply to the workspace screens                                                      
  91     private static final float WORKSPACE_OVERSCROLL_ROTATION = 24f;                                      
  92                                                                                                          
  93     private static final int CHILDREN_OUTLINE_FADE_OUT_DELAY = 0;                                        
  94                                                                                                          
  95     private static final int CHILDREN_OUTLINE_FADE_OUT_DURATION = 375;                                   
  96                                                                                                          
  97     private static final int CHILDREN_OUTLINE_FADE_IN_DURATION = 100;                                    
  98                                                                                                          
  99     protected static final int SNAP_OFF_EMPTY_SCREEN_DURATION = 400;                                     
 100                                                                                                          
 101     protected static final int FADE_EMPTY_SCREEN_DURATION = 150;                                         
 102                                                                                                          
 103     private static final int BACKGROUND_FADE_OUT_DURATION = 350;                                         
 104                                                                                                          
 105     private static final int ADJACENT_SCREEN_DROP_DURATION = 300;                                        
 106                                                                                                          
 107     private static final int FLING_THRESHOLD_VELOCITY = 500;                                             
 108                                                                                                          
 109     private static final float ALPHA_CUTOFF_THRESHOLD = 0.01f;                                           
 110                                                                                                          
 111     static final boolean MAP_NO_RECURSE = false;                                                         
 112                                                                                                          
 113     static final boolean MAP_RECURSE = true;                                                             
 114                                                                                                          
 115     // These animators are used to fade the children's outlines                                          
 116     // These animators are used to fade the children's outlines                                          
 117     private ObjectAnimator mChildrenOutlineFadeInAnimation;                                              
 118                                                                                                          
 119     private ObjectAnimator mChildrenOutlineFadeOutAnimation;                                             
 120                                                                                                          
 121     private float mChildrenOutlineAlpha = 0;                                                             
 122                                                                                                          
 123     // These properties refer to the background protection gradient used for AllApps and Customize       
 124     // These properties refer to the background protection gradient used for AllApps and Customize       
 125     private ValueAnimator mBackgroundFadeInAnimation;                                                    
 126                                                                                                          
 127     private ValueAnimator mBackgroundFadeOutAnimation;                                                   
 128                                                                                                          
 129     private static final long CUSTOM_CONTENT_GESTURE_DELAY = 200;                                        
 130                                                                                                          
 131     private long mTouchDownTime = -1;                                                                    
 132                                                                                                          
 133     private long mCustomContentShowTime = -1;                                                            
 134                                                                                                          
 135     private LayoutTransition mLayoutTransition;                                                          
 136                                                                                                          
 137     private final WallpaperManager mWallpaperManager;                                                    
 138                                                                                                          
 139     private IBinder mWindowToken;                                                                        
 140                                                                                                          
 141     private int mOriginalDefaultPage;                                                                    
 142                                                                                                          
 143     private int mDefaultPage;                                                                            
 144                                                                                                          
 145     private ShortcutAndWidgetContainer mDragSourceInternal;                                              
 146                                                                                                          
 147     private static boolean sAccessibilityEnabled;                                                        
 148                                                                                                          
 149     // The screen id used for the empty screen always present to the right.                              
 150     static final long EXTRA_EMPTY_SCREEN_ID = -201;                                                      
 151                                                                                                          
 152     private final static long CUSTOM_CONTENT_SCREEN_ID = -301;                                           
 153                                                                                                          
 154     private HashMap<Long, CellLayout> mWorkspaceScreens = new HashMap<Long, CellLayout>();               
 155                                                                                                          
 156     private ArrayList<Long> mScreenOrder = new ArrayList<Long>();                                        
 157                                                                                                          
 158     private Runnable mRemoveEmptyScreenRunnable;                                                         
 159                                                                                                          
 160     private boolean mDeferRemoveExtraEmptyScreen = false;                                                
 161                                                                                                          
 162     /**                                                                                                  
 163      * CellInfo for the cell that is currently being dragged                                             
 164      */                                                                                                  
 165     private CellLayout.CellInfo mDragInfo;                                                               
 166                                                                                                          
 167     /**                                                                                                  
 168      * Target drop area calculated during last acceptDrop call.                                          
 169      */                                                                                                  
 170     private int[] mTargetCell = new int[2];                                                              
 171                                                                                                          
 172     private int mDragOverX = -1;                                                                         
 173                                                                                                          
 174     private int mDragOverY = -1;                                                                         
 175                                                                                                          
 176     static Rect mLandscapeCellLayoutMetrics = null;                                                      
 177                                                                                                          
 178     static Rect mPortraitCellLayoutMetrics = null;                                                       
 179                                                                                                          
 180     CustomContentCallbacks mCustomContentCallbacks;                                                      
 181                                                                                                          
 182     boolean mCustomContentShowing;                                                                       
 183                                                                                                          
 184     private float mLastCustomContentScrollProgress = -1f;                                                
 185                                                                                                          
 186     private String mCustomContentDescription = "";                                                       
 187                                                                                                          
 188     /**                                                                                                  
 189      * The CellLayout that is currently being dragged over                                               
 190      */                                                                                                  
 191     private CellLayout mDragTargetLayout = null;                                                         
 192                                                                                                          
 193     /**                                                                                                  
 194      * The CellLayout that we will show as glowing                                                       
 195      */                                                                                                  
 196     private CellLayout mDragOverlappingLayout = null;                                                    
 197                                                                                                          
 198     /**                                                                                                  
 199      * The CellLayout which will be dropped to                                                           
 200      */                                                                                                  
 201     private CellLayout mDropToLayout = null;                                                             
 202                                                                                                          
 203     private Launcher mLauncher;                                                                          
 204                                                                                                          
 205     private IconCache mIconCache;                                                                        
 206                                                                                                          
 207     private DragController mDragController;                                                              
 208                                                                                                          
 209     // These are temporary variables to prevent having to allocate a new object just to                  
 210     // return an (x, y) value from helper functions. Do NOT use them to maintain other state.            
 211     private int[] mTempCell = new int[2];                                                                
 212                                                                                                          
 213     private int[] mTempPt = new int[2];                                                                  
 214                                                                                                          
 215     private int[] mTempEstimate = new int[2];                                                            
 216                                                                                                          
 217     private float[] mDragViewVisualCenter = new float[2];                                                
 218                                                                                                          
 219     private float[] mTempCellLayoutCenterCoordinates = new float[2];                                     
 220                                                                                                          
 221     private Matrix mTempInverseMatrix = new Matrix();                                                    
 222                                                                                                          
 223     private SpringLoadedDragController mSpringLoadedDragController;                                      
 224                                                                                                          
 225     private float mSpringLoadedShrinkFactor;                                                             
 226                                                                                                          
 227     private float mOverviewModeShrinkFactor;                                                             
 228                                                                                                          
 229     // State variable that indicates whether the pages are small (ie when you're                         
 230     // in all apps or customize mode)                                                                    
 231     enum State {                                                                                         
 232                                                                                                          
 233     NORMAL,                                                                                              
 234         NORMAL_HIDDEN,                                                                                   
 235     SPRING_LOADED,                                                                                       
 236     OVERVIEW,                                                                                            
 237     OVERVIEW_HIDDEN;}                                                                                    
 238                                                                                                          
 239     private State mState = State.NORMAL;                                                                 
 240                                                                                                          
 241     private boolean mIsSwitchingState = false;                                                           
 242                                                                                                          
 243     boolean mAnimatingViewIntoPlace = false;                                                             
 244                                                                                                          
 245     boolean mIsDragOccuring = false;                                                                     
 246                                                                                                          
 247     boolean mChildrenLayersEnabled = true;                                                               
 248                                                                                                          
 249     private boolean mStripScreensOnPageStopMoving = false;                                               
 250                                                                                                          
 251     /** Is the user is dragging an item near the edge of a page? */                                      
 252     private boolean mInScrollArea = false;                                                               
 253                                                                                                          
 254     private HolographicOutlineHelper mOutlineHelper;                                                     
 255                                                                                                          
 256     private Bitmap mDragOutline = null;                                                                  
 257                                                                                                          
 258     private static final Rect sTempRect = new Rect();                                                    
 259                                                                                                          
 260     private final int[] mTempXY = new int[2];                                                            
 261                                                                                                          
 262     private int[] mTempVisiblePagesRange = new int[2];                                                   
 263                                                                                                          
 264     private boolean mOverscrollEffectSet;                                                                
 265                                                                                                          
 266     public static final int DRAG_BITMAP_PADDING = 2;                                                     
 267                                                                                                          
 268     private boolean mWorkspaceFadeInAdjacentScreens;                                                     
 269                                                                                                          
 270     WallpaperOffsetInterpolator mWallpaperOffset;                                                        
 271                                                                                                          
 272     private boolean mWallpaperIsLiveWallpaper;                                                           
 273                                                                                                          
 274     private int mNumPagesForWallpaperParallax;                                                           
 275                                                                                                          
 276     private float mLastSetWallpaperOffsetSteps = 0;                                                      
 277                                                                                                          
 278     private Runnable mDelayedResizeRunnable;                                                             
 279                                                                                                          
 280     private Runnable mDelayedSnapToPageRunnable;                                                         
 281                                                                                                          
 282     private Point mDisplaySize = new Point();                                                            
 283                                                                                                          
 284     private int mCameraDistance;                                                                         
 285                                                                                                          
 286     // Variables relating to the creation of user folders by hovering shortcuts over shortcuts           
 287     // Variables relating to the creation of user folders by hovering shortcuts over shortcuts           
 288     private static final int FOLDER_CREATION_TIMEOUT = 0;                                                
 289                                                                                                          
 290     public static final int REORDER_TIMEOUT = 350;                                                       
 291                                                                                                          
 292     private final Alarm mFolderCreationAlarm = new Alarm();                                              
 293                                                                                                          
 294     private final Alarm mReorderAlarm = new Alarm();                                                     
 295                                                                                                          
 296     private FolderRingAnimator mDragFolderRingAnimator = null;                                           
 297                                                                                                          
 298     private FolderIcon mDragOverFolderIcon = null;                                                       
 299                                                                                                          
 300     private boolean mCreateUserFolderOnDrop = false;                                                     
 301                                                                                                          
 302     private boolean mAddToExistingFolderOnDrop = false;                                                  
 303                                                                                                          
 304     private DropTarget.DragEnforcer mDragEnforcer;                                                       
 305                                                                                                          
 306     private float mMaxDistanceForFolderCreation;                                                         
 307                                                                                                          
 308     private final Canvas mCanvas = new Canvas();                                                         
 309                                                                                                          
 310     // Variables relating to touch disambiguation (scrolling workspace vs. scrolling a widget)           
 311     // Variables relating to touch disambiguation (scrolling workspace vs. scrolling a widget)           
 312     private float mXDown;                                                                                
 313                                                                                                          
 314     private float mYDown;                                                                                
 315                                                                                                          
 316     final static float START_DAMPING_TOUCH_SLOP_ANGLE = (float) Math.PI / 6;                             
 317                                                                                                          
 318     final static float MAX_SWIPE_ANGLE = (float) Math.PI / 3;                                            
 319                                                                                                          
 320     final static float TOUCH_SLOP_DAMPING_FACTOR = 4;                                                    
 321                                                                                                          
 322     // Relating to the animation of items being dropped externally                                       
 323     // Relating to the animation of items being dropped externally                                       
 324     public static final int ANIMATE_INTO_POSITION_AND_DISAPPEAR = 0;                                     
 325                                                                                                          
 326     public static final int ANIMATE_INTO_POSITION_AND_REMAIN = 1;                                        
 327                                                                                                          
 328     public static final int ANIMATE_INTO_POSITION_AND_RESIZE = 2;                                        
 329                                                                                                          
 330     public static final int COMPLETE_TWO_STAGE_WIDGET_DROP_ANIMATION = 3;                                
 331                                                                                                          
 332     public static final int CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION = 4;                                  
 333                                                                                                          
 334     // Related to dragging, folder creation and reordering                                               
 335     private static final int DRAG_MODE_NONE = 0;                                                         
 336                                                                                                          
 337     private static final int DRAG_MODE_CREATE_FOLDER = 1;                                                
 338                                                                                                          
 339     private static final int DRAG_MODE_ADD_TO_FOLDER = 2;                                                
 340                                                                                                          
 341     private static final int DRAG_MODE_REORDER = 3;                                                      
 342                                                                                                          
 343     private int mDragMode = DRAG_MODE_NONE;                                                              
 344                                                                                                          
 345     private int mLastReorderX = -1;                                                                      
 346                                                                                                          
 347     private int mLastReorderY = -1;                                                                      
 348                                                                                                          
 349     private SparseArray<Parcelable> mSavedStates;                                                        
 350                                                                                                          
 351     private final ArrayList<Integer> mRestoredPages = new ArrayList<Integer>();                          
 352                                                                                                          
 353     // These variables are used for storing the initial and final values during workspace animations     
 354     // These variables are used for storing the initial and final values during workspace animations     
 355     private int mSavedScrollX;                                                                           
 356                                                                                                          
 357     private float mSavedRotationY;                                                                       
 358                                                                                                          
 359     private float mSavedTranslationX;                                                                    
 360                                                                                                          
 361     private float mCurrentScale;                                                                         
 362                                                                                                          
 363     private float mNewScale;                                                                             
 364                                                                                                          
 365     private float[] mOldBackgroundAlphas;                                                                
 366                                                                                                          
 367     private float[] mOldAlphas;                                                                          
 368                                                                                                          
 369     private float[] mNewBackgroundAlphas;                                                                
 370                                                                                                          
 371     private float[] mNewAlphas;                                                                          
 372                                                                                                          
 373     private int mLastChildCount = -1;                                                                    
 374                                                                                                          
 375     private float mTransitionProgress;                                                                   
 376                                                                                                          
 377     float mOverScrollEffect = 0f;                                                                        
 378                                                                                                          
 379     private Runnable mDeferredAction;                                                                    
 380                                                                                                          
 381     private boolean mDeferDropAfterUninstall;                                                            
 382                                                                                                          
 383     private boolean mUninstallSuccessful;                                                                
 384                                                                                                          
 385     private final Runnable mBindPages = new Runnable() {                                                 
 386         @Override                                                                                        
 387         public void run() {                                                                              
 388             mLauncher.getModel().bindRemainingSynchronousPages();                                        
 389         }                                                                                                
 390     };                                                                                                   
 391                                                                                                          
 392     /**                                                                                                  
 393      * Used to inflate the Workspace from XML.                                                           
 394      *                                                                                                   
 395      * @param context                                                                                    
 396      * 		The application's context.                                                                      
 397      * @param attrs                                                                                      
 398      * 		The attributes set containing the Workspace's customization values.                             
 399      */                                                                                                  
 400     public Workspace(Context context, AttributeSet attrs) {                                              
 401         this(context, attrs, 0);                                                                         
 402     }                                                                                                    
 403                                                                                                          
 404     /**                                                                                                  
 405      * Used to inflate the Workspace from XML.                                                           
 406      *                                                                                                   
 407      * @param context                                                                                    
 408      * 		The application's context.                                                                      
 409      * @param attrs                                                                                      
 410      * 		The attributes set containing the Workspace's customization values.                             
 411      * @param defStyle                                                                                   
 412      * 		Unused.                                                                                         
 413      */                                                                                                  
 414     public Workspace(Context context, AttributeSet attrs, int defStyle) {                                
 415         super(context, attrs, defStyle);                                                                 
 416         mContentIsRefreshable = false;                                                                   
 417         mOutlineHelper = HolographicOutlineHelper.obtain(context);                                       
 418         mDragEnforcer = new DropTarget.DragEnforcer(context);                                            
 419         // With workspace, data is available straight from the get-go                                    
 420         setDataIsReady();                                                                                
 421         mLauncher = ((Launcher) (context));                                                              
 422         final Resources res = getResources();                                                            
 423         mWorkspaceFadeInAdjacentScreens = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfil🔵
 424         mFadeInAdjacentScreens = false;                                                                  
 425         mWallpaperManager = WallpaperManager.getInstance(context);                                       
 426         LauncherAppState app = LauncherAppState.getInstance();                                           
 427         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                    
 428         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Workspace, defStyle, 0);        
 429         mSpringLoadedShrinkFactor = res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) 🔵
 430         mOverviewModeShrinkFactor = grid.getOverviewModeScale();                                         
 431         mCameraDistance = res.getInteger(R.integer.config_cameraDistance);                               
 432         mOriginalDefaultPage = mDefaultPage = a.getInt(R.styleable.Workspace_defaultScreen, 1);          
 433         a.recycle();                                                                                     
 434         setOnHierarchyChangeListener(this);                                                              
 435         setHapticFeedbackEnabled(false);                                                                 
 436         initWorkspace();                                                                                 
 437         // Disable multitouch across the workspace/all apps/customize tray                               
 438         setMotionEventSplittingEnabled(true);                                                            
 439         setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);                              
 440     }                                                                                                    
 441                                                                                                          
 442     @Override                                                                                            
 443     public void setInsets(Rect insets) {                                                                 
 444         mInsets.set(insets);                                                                             
 445                                                                                                          
 446         CellLayout customScreen = getScreenWithId(CUSTOM_CONTENT_SCREEN_ID);                             
 447         if (customScreen != null) {                                                                      
 448             View customContent = customScreen.getShortcutsAndWidgets().getChildAt(0);                    
 449             if (customContent instanceof Insettable) {                                                   
 450                 ((Insettable) customContent).setInsets(mInsets);                                         
 451             }                                                                                            
 452         }                                                                                                
 453     }                                                                                                    
 454                                                                                                          
 455     // estimate the size of a widget with spans hSpan, vSpan. return MAX_VALUE for each                  
 456     // dimension if unsuccessful                                                                         
 457     public int[] estimateItemSize(int hSpan, int vSpan,                                                  
 458             ItemInfo itemInfo, boolean springLoaded) {                                                   
 459         int[] size = new int[2];                                                                         
 460         if (getChildCount() > 0) {                                                                       
 461             // Use the first non-custom page to estimate the child position                              
 462             CellLayout cl = (CellLayout) getChildAt(numCustomPages());                                   
 463             Rect r = estimateItemPosition(cl, itemInfo, 0, 0, hSpan, vSpan);                             
 464             size[0] = r.width();                                                                         
 465             size[1] = r.height();                                                                        
 466             if (springLoaded) {                                                                          
 467                 size[0] *= mSpringLoadedShrinkFactor;                                                    
 468                 size[1] *= mSpringLoadedShrinkFactor;                                                    
 469             }                                                                                            
 470             return size;                                                                                 
 471         } else {                                                                                         
 472             size[0] = Integer.MAX_VALUE;                                                                 
 473             size[1] = Integer.MAX_VALUE;                                                                 
 474             return size;                                                                                 
 475         }                                                                                                
 476     }                                                                                                    
 477                                                                                                          
 478     public Rect estimateItemPosition(CellLayout cl, ItemInfo pendingInfo,                                
 479             int hCell, int vCell, int hSpan, int vSpan) {                                                
 480         Rect r = new Rect();                                                                             
 481         cl.cellToRect(hCell, vCell, hSpan, vSpan, r);                                                    
 482         return r;                                                                                        
 483     }                                                                                                    
 484                                                                                                          
 485     public void onDragStart(final DragSource source, Object info, int dragAction) {                      
 486         mIsDragOccuring = true;                                                                          
 487         updateChildrenLayersEnabled(false);                                                              
 488         mLauncher.lockScreenOrientation();                                                               
 489         mLauncher.onInteractionBegin();                                                                  
 490         setChildrenBackgroundAlphaMultipliers(1.0F);                                                     
 491         // Prevent any Un/InstallShortcutReceivers from updating the db while we are dragging            
 492         InstallShortcutReceiver.enableInstallQueue();                                                    
 493         UninstallShortcutReceiver.enableUninstallQueue();                                                
 494         post(new Runnable() {                                                                            
 495             @Override                                                                                    
 496             public void run() {                                                                          
 497                 if (mIsDragOccuring) {                                                                   
 498                     mDeferRemoveExtraEmptyScreen = false;                                                
 499                     addExtraEmptyScreenOnDrag();                                                         
 500                 }                                                                                        
 501             }                                                                                            
 502         });                                                                                              
 503     }                                                                                                    
 504                                                                                                          
 505     public void deferRemoveExtraEmptyScreen() {                                                          
 506         mDeferRemoveExtraEmptyScreen = true;                                                             
 507     }                                                                                                    
 508                                                                                                          
 509     public void onDragEnd() {                                                                            
 510         if (!mDeferRemoveExtraEmptyScreen) {                                                             
 511             removeExtraEmptyScreen(true, mDragSourceInternal != null);                                   
 512         }                                                                                                
 513         mIsDragOccuring = false;                                                                         
 514         updateChildrenLayersEnabled(false);                                                              
 515         mLauncher.unlockScreenOrientation(false);                                                        
 516         // Re-enable any Un/InstallShortcutReceiver and now process any queued items                     
 517         InstallShortcutReceiver.disableAndFlushInstallQueue(getContext());                               
 518         UninstallShortcutReceiver.disableAndFlushUninstallQueue(getContext());                           
 519         mDragSourceInternal = null;                                                                      
 520         mLauncher.onInteractionEnd();                                                                    
 521     }                                                                                                    
 522                                                                                                          
 523     /**                                                                                                  
 524      * Initializes various states for this workspace.                                                    
 525      */                                                                                                  
 526     protected void initWorkspace() {                                                                     
 527         mCurrentPage = mDefaultPage;                                                                     
 528         Launcher.setScreen(mCurrentPage);                                                                
 529         LauncherAppState app = LauncherAppState.getInstance();                                           
 530         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                    
 531         mIconCache = app.getIconCache();                                                                 
 532         setWillNotDraw(false);                                                                           
 533         setClipChildren(false);                                                                          
 534         setClipToPadding(false);                                                                         
 535         setChildrenDrawnWithCacheEnabled(true);                                                          
 536         setMinScale(mOverviewModeShrinkFactor);                                                          
 537         setupLayoutTransition();                                                                         
 538         mWallpaperOffset = new WallpaperOffsetInterpolator();                                            
 539         Display display = mLauncher.getWindowManager().getDefaultDisplay();                              
 540         display.getSize(mDisplaySize);                                                                   
 541         mMaxDistanceForFolderCreation = 0.55F * grid.iconSizePx;                                         
 542         mFlingThresholdVelocity = ((int) (FLING_THRESHOLD_VELOCITY * mDensity));                         
 543         // Set the wallpaper dimensions when Launcher starts up                                          
 544         setWallpaperDimension();                                                                         
 545     }                                                                                                    
 546                                                                                                          
 547     private void setupLayoutTransition() {                                                               
 548         // We want to show layout transitions when pages are deleted, to close the gap.                  
 549         mLayoutTransition = new LayoutTransition();                                                      
 550         mLayoutTransition.enableTransitionType(LayoutTransition.DISAPPEARING);                           
 551         mLayoutTransition.enableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);                    
 552         mLayoutTransition.disableTransitionType(LayoutTransition.APPEARING);                             
 553         mLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_APPEARING);                      
 554         setLayoutTransition(mLayoutTransition);                                                          
 555     }                                                                                                    
 556                                                                                                          
 557     void enableLayoutTransitions() {                                                                     
 558         setLayoutTransition(mLayoutTransition);                                                          
 559     }                                                                                                    
 560                                                                                                          
 561     void disableLayoutTransitions() {                                                                    
 562         setLayoutTransition(null);                                                                       
 563     }                                                                                                    
 564                                                                                                          
 565     @Override                                                                                            
 566     protected int getScrollMode() {                                                                      
 567         return SmoothPagedView.X_LARGE_MODE;                                                             
 568     }                                                                                                    
 569                                                                                                          
 570     @Override                                                                                            
 571     public void onChildViewAdded(View parent, View child) {                                              
 572         if (!(child instanceof CellLayout)) {                                                            
 573             throw new IllegalArgumentException("A Workspace can only have CellLayout children.");        
 574         }                                                                                                
 575         CellLayout cl = ((CellLayout) child);                                                            
 576         cl.setOnInterceptTouchListener(this);                                                            
 577         cl.setClickable(true);                                                                           
 578         cl.setImportantForAccessibility(ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO);                      
 579         super.onChildViewAdded(parent, child);                                                           
 580     }                                                                                                    
 581                                                                                                          
 582     protected boolean shouldDrawChild(View child) {                                                      
 583         final CellLayout cl = (CellLayout) child;                                                        
 584         return super.shouldDrawChild(child) &&                                                           
 585             (mIsSwitchingState ||                                                                        
 586              cl.getShortcutsAndWidgets().getAlpha() > 0 ||                                               
 587              cl.getBackgroundAlpha() > 0);                                                               
 588     }                                                                                                    
 589                                                                                                          
 590     /**                                                                                                  
 591      * @return The open folder on the current screen, or null if there is none                           
 592      */                                                                                                  
 593     Folder getOpenFolder() {                                                                             
 594         DragLayer dragLayer = mLauncher.getDragLayer();                                                  
 595         int count = dragLayer.getChildCount();                                                           
 596         for (int i = 0; i < count; i++) {                                                                
 597             View child = dragLayer.getChildAt(i);                                                        
 598             if (child instanceof Folder) {                                                               
 599                 Folder folder = (Folder) child;                                                          
 600                 if (folder.getInfo().opened)                                                             
 601                     return folder;                                                                       
 602             }                                                                                            
 603         }                                                                                                
 604         return null;                                                                                     
 605     }                                                                                                    
 606                                                                                                          
 607     boolean isTouchActive() {                                                                            
 608         return mTouchState != TOUCH_STATE_REST;                                                          
 609     }                                                                                                    
 610                                                                                                          
 611     public void removeAllWorkspaceScreens() {                                                            
 612         // Disable all layout transitions before removing all pages to ensure that we don't get the      
 613         // transition animations competing with us changing the scroll when we add pages or the          
 614         // custom content screen                                                                         
 615         disableLayoutTransitions();                                                                      
 616                                                                                                          
 617         // Since we increment the current page when we call addCustomContentPage via bindScreens         
 618         // (and other places), we need to adjust the current page back when we clear the pages           
 619         if (hasCustomContent()) {                                                                        
 620             removeCustomContentPage();                                                                   
 621         }                                                                                                
 622                                                                                                          
 623         // Remove the pages and clear the screen models                                                  
 624         removeAllViews();                                                                                
 625         mScreenOrder.clear();                                                                            
 626         mWorkspaceScreens.clear();                                                                       
 627                                                                                                          
 628         // Re-enable the layout transitions                                                              
 629         enableLayoutTransitions();                                                                       
 630     }                                                                                                    
 631                                                                                                          
 632     public long insertNewWorkspaceScreenBeforeEmptyScreen(long screenId) {                               
 633         // Find the index to insert this view into.  If the empty screen exists, then                    
 634         // insert it before that.                                                                        
 635         int insertIndex = mScreenOrder.indexOf(EXTRA_EMPTY_SCREEN_ID);                                   
 636         if (insertIndex < 0) {                                                                           
 637             insertIndex = mScreenOrder.size();                                                           
 638         }                                                                                                
 639         return insertNewWorkspaceScreen(screenId, insertIndex);                                          
 640     }                                                                                                    
 641                                                                                                          
 642     public long insertNewWorkspaceScreen(long screenId) {                                                
 643         return insertNewWorkspaceScreen(screenId, getChildCount());                                      
 644     }                                                                                                    
 645                                                                                                          
 646     public long insertNewWorkspaceScreen(long screenId, int insertIndex) {                               
 647         // Log to disk                                                                                   
 648         Launcher.addDumpLog(TAG, "11683562 - insertNewWorkspaceScreen(): " + screenId +                  
 649                 " at index: " + insertIndex, true);                                                      
 650                                                                                                          
 651         if (mWorkspaceScreens.containsKey(screenId)) {                                                   
 652             throw new RuntimeException("Screen id " + screenId + " already exists!");                    
 653         }                                                                                                
 654                                                                                                          
 655         CellLayout newScreen = (CellLayout)                                                              
 656                 mLauncher.getLayoutInflater().inflate(R.layout.workspace_screen, null);                  
 657                                                                                                          
 658         newScreen.setOnLongClickListener(mLongClickListener);                                            
 659         newScreen.setOnClickListener(mLauncher);                                                         
 660         newScreen.setSoundEffectsEnabled(false);                                                         
 661         mWorkspaceScreens.put(screenId, newScreen);                                                      
 662         mScreenOrder.add(insertIndex, screenId);                                                         
 663         addView(newScreen, insertIndex);                                                                 
 664         return screenId;                                                                                 
 665     }                                                                                                    
 666                                                                                                          
 667     public void createCustomContentContainer() {                                                         
 668         CellLayout customScreen = ((CellLayout) (mLauncher.getLayoutInflater().inflate(R.layout.workspace🔵
 669         customScreen.disableBackground();                                                                
 670         customScreen.disableDragTarget();                                                                
 671         mWorkspaceScreens.put(CUSTOM_CONTENT_SCREEN_ID, customScreen);                                   
 672         mScreenOrder.add(0, CUSTOM_CONTENT_SCREEN_ID);                                                   
 673         // We want no padding on the custom content                                                      
 674         customScreen.setPadding(0, 0, 0, 0);                                                             
 675         addFullScreenPage(customScreen);                                                                 
 676         // Ensure that the current page and default page are maintained.                                 
 677         mDefaultPage = mOriginalDefaultPage + 1;                                                         
 678         // Update the custom content hint                                                                
 679         if (mRestorePage != INVALID_RESTORE_PAGE) {                                                      
 680             mRestorePage = mRestorePage + 1;                                                             
 681         } else {                                                                                         
 682             setCurrentPage(getCurrentPage() + 1);                                                        
 683         }                                                                                                
 684     }                                                                                                    
 685                                                                                                          
 686     public void removeCustomContentPage() {                                                              
 687         CellLayout customScreen = getScreenWithId(CUSTOM_CONTENT_SCREEN_ID);                             
 688         if (customScreen == null) {                                                                      
 689             throw new RuntimeException("Expected custom content screen to exist");                       
 690         }                                                                                                
 691         mWorkspaceScreens.remove(CUSTOM_CONTENT_SCREEN_ID);                                              
 692         mScreenOrder.remove(CUSTOM_CONTENT_SCREEN_ID);                                                   
 693         removeView(customScreen);                                                                        
 694         if (mCustomContentCallbacks != null) {                                                           
 695             mCustomContentCallbacks.onScrollProgressChanged(0);                                          
 696             mCustomContentCallbacks.onHide();                                                            
 697         }                                                                                                
 698         mCustomContentCallbacks = null;                                                                  
 699         // Ensure that the current page and default page are maintained.                                 
 700         mDefaultPage = mOriginalDefaultPage - 1;                                                         
 701         // Update the custom content hint                                                                
 702         if (mRestorePage != INVALID_RESTORE_PAGE) {                                                      
 703             mRestorePage = mRestorePage - 1;                                                             
 704         } else {                                                                                         
 705             setCurrentPage(getCurrentPage() - 1);                                                        
 706         }                                                                                                
 707     }                                                                                                    
 708                                                                                                          
 709     public void addToCustomContentPage(View customContent, CustomContentCallbacks callbacks,             
 710             String description) {                                                                        
 711         if (getPageIndexForScreenId(CUSTOM_CONTENT_SCREEN_ID) < 0) {                                     
 712             throw new RuntimeException("Expected custom content screen to exist");                       
 713         }                                                                                                
 714                                                                                                          
 715         // Add the custom content to the full screen custom page                                         
 716         CellLayout customScreen = getScreenWithId(CUSTOM_CONTENT_SCREEN_ID);                             
 717         int spanX = customScreen.getCountX();                                                            
 718         int spanY = customScreen.getCountY();                                                            
 719         CellLayout.LayoutParams lp = new CellLayout.LayoutParams(0, 0, spanX, spanY);                    
 720         lp.canReorder  = false;                                                                          
 721         lp.isFullscreen = true;                                                                          
 722         if (customContent instanceof Insettable) {                                                       
 723             ((Insettable)customContent).setInsets(mInsets);                                              
 724         }                                                                                                
 725                                                                                                          
 726         // Verify that the child is removed from any existing parent.                                    
 727         if (customContent.getParent() instanceof ViewGroup) {                                            
 728             ViewGroup parent = (ViewGroup) customContent.getParent();                                    
 729             parent.removeView(customContent);                                                            
 730         }                                                                                                
 731         customScreen.removeAllViews();                                                                   
 732         customScreen.addViewToCellLayout(customContent, 0, 0, lp, true);                                 
 733         mCustomContentDescription = description;                                                         
 734                                                                                                          
 735         mCustomContentCallbacks = callbacks;                                                             
 736     }                                                                                                    
 737                                                                                                          
 738     public void addExtraEmptyScreenOnDrag() {                                                            
 739         // Log to disk                                                                                   
 740         Launcher.addDumpLog(TAG, "11683562 - addExtraEmptyScreenOnDrag()", true);                        
 741                                                                                                          
 742         boolean lastChildOnScreen = false;                                                               
 743         boolean childOnFinalScreen = false;                                                              
 744                                                                                                          
 745         // Cancel any pending removal of empty screen                                                    
 746         mRemoveEmptyScreenRunnable = null;                                                               
 747                                                                                                          
 748         if (mDragSourceInternal != null) {                                                               
 749             if (mDragSourceInternal.getChildCount() == 1) {                                              
 750                 lastChildOnScreen = true;                                                                
 751             }                                                                                            
 752             CellLayout cl = (CellLayout) mDragSourceInternal.getParent();                                
 753             if (indexOfChild(cl) == getChildCount() - 1) {                                               
 754                 childOnFinalScreen = true;                                                               
 755             }                                                                                            
 756         }                                                                                                
 757                                                                                                          
 758         // If this is the last item on the final screen                                                  
 759         if (lastChildOnScreen && childOnFinalScreen) {                                                   
 760             return;                                                                                      
 761         }                                                                                                
 762         if (!mWorkspaceScreens.containsKey(EXTRA_EMPTY_SCREEN_ID)) {                                     
 763             insertNewWorkspaceScreen(EXTRA_EMPTY_SCREEN_ID);                                             
 764         }                                                                                                
 765     }                                                                                                    
 766                                                                                                          
 767     public boolean addExtraEmptyScreen() {                                                               
 768         // Log to disk                                                                                   
 769         Launcher.addDumpLog(TAG, "11683562 - addExtraEmptyScreen()", true);                              
 770                                                                                                          
 771         if (!mWorkspaceScreens.containsKey(EXTRA_EMPTY_SCREEN_ID)) {                                     
 772             insertNewWorkspaceScreen(EXTRA_EMPTY_SCREEN_ID);                                             
 773             return true;                                                                                 
 774         }                                                                                                
 775         return false;                                                                                    
 776     }                                                                                                    
 777                                                                                                          
 778     private void convertFinalScreenToEmptyScreenIfNecessary() {                                          
 779         // Log to disk                                                                                   
 780         Launcher.addDumpLog(TAG, "11683562 - convertFinalScreenToEmptyScreenIfNecessary()", true);       
 781         if (mLauncher.isWorkspaceLoading()) {                                                            
 782             // Invalid and dangerous operation if workspace is loading                                   
 783             Launcher.addDumpLog(TAG, "    - workspace loading, skip", true);                             
 784             return;                                                                                      
 785         }                                                                                                
 786         if (hasExtraEmptyScreen() || (mScreenOrder.size() == 0)) {                                       
 787             return;                                                                                      
 788         }                                                                                                
 789         long finalScreenId = mScreenOrder.get(mScreenOrder.size() - 1);                                  
 790         if (finalScreenId == CUSTOM_CONTENT_SCREEN_ID) {                                                 
 791             return;                                                                                      
 792         }                                                                                                
 793         CellLayout finalScreen = mWorkspaceScreens.get(finalScreenId);                                   
 794         // If the final screen is empty, convert it to the extra empty screen                            
 795         if ((finalScreen.getShortcutsAndWidgets().getChildCount() == 0) && (!finalScreen.isDropPending())🔵
 796             mWorkspaceScreens.remove(finalScreenId);                                                     
 797             mScreenOrder.remove(finalScreenId);                                                          
 798             // if this is the last non-custom content screen, convert it to the empty screen             
 799             mWorkspaceScreens.put(EXTRA_EMPTY_SCREEN_ID, finalScreen);                                   
 800             mScreenOrder.add(EXTRA_EMPTY_SCREEN_ID);                                                     
 801             // Update the model if we have changed any screens                                           
 802             mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder);                    
 803             Launcher.addDumpLog(TAG, "11683562 -   extra empty screen: " + finalScreenId, true);         
 804         }                                                                                                
 805     }                                                                                                    
 806                                                                                                          
 807     public void removeExtraEmptyScreen(final boolean animate, boolean stripEmptyScreens) {               
 808         removeExtraEmptyScreenDelayed(animate, null, 0, stripEmptyScreens);                              
 809     }                                                                                                    
 810                                                                                                          
 811     public void removeExtraEmptyScreenDelayed(final boolean animate, final Runnable onComplete, final int🔵
 812         // Log to disk                                                                                   
 813         Launcher.addDumpLog(TAG, "11683562 - removeExtraEmptyScreen()", true);                           
 814         if (mLauncher.isWorkspaceLoading()) {                                                            
 815             // Don't strip empty screens if the workspace is still loading                               
 816             Launcher.addDumpLog(TAG, "    - workspace loading, skip", true);                             
 817             return;                                                                                      
 818         }                                                                                                
 819         if (delay > 0) {                                                                                 
 820             postDelayed(new Runnable() {                                                                 
 821                 @Override                                                                                
 822                 public void run() {                                                                      
 823                     removeExtraEmptyScreenDelayed(animate, onComplete, 0, stripEmptyScreens);            
 824                 }                                                                                        
 825             }, delay);                                                                                   
 826             return;                                                                                      
 827         }                                                                                                
 828         convertFinalScreenToEmptyScreenIfNecessary();                                                    
 829         if (hasExtraEmptyScreen()) {                                                                     
 830             int emptyIndex = mScreenOrder.indexOf(EXTRA_EMPTY_SCREEN_ID);                                
 831             if (getNextPage() == emptyIndex) {                                                           
 832                 snapToPage(getNextPage() - 1, SNAP_OFF_EMPTY_SCREEN_DURATION);                           
 833                 fadeAndRemoveEmptyScreen(SNAP_OFF_EMPTY_SCREEN_DURATION, FADE_EMPTY_SCREEN_DURATION, onCo🔵
 834             } else {                                                                                     
 835                 fadeAndRemoveEmptyScreen(0, FADE_EMPTY_SCREEN_DURATION, onComplete, stripEmptyScreens);  
 836             }                                                                                            
 837             return;                                                                                      
 838         } else if (stripEmptyScreens) {                                                                  
 839             // If we're not going to strip the empty screens after removing                              
 840             // the extra empty screen, do it right away.                                                 
 841             stripEmptyScreens();                                                                         
 842         }                                                                                                
 843         if (onComplete != null) {                                                                        
 844             onComplete.run();                                                                            
 845         }                                                                                                
 846     }                                                                                                    
 847                                                                                                          
 848     private void fadeAndRemoveEmptyScreen(int delay, int duration, final Runnable onComplete,            
 849             final boolean stripEmptyScreens) {                                                           
 850         // Log to disk                                                                                   
 851         // XXX: Do we need to update LM workspace screens below?                                         
 852         Launcher.addDumpLog(TAG, "11683562 - fadeAndRemoveEmptyScreen()", true);                         
 853         PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 0f);                          
 854         PropertyValuesHolder bgAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha", 0f);              
 855                                                                                                          
 856         final CellLayout cl = mWorkspaceScreens.get(EXTRA_EMPTY_SCREEN_ID);                              
 857                                                                                                          
 858         mRemoveEmptyScreenRunnable = new Runnable() {                                                    
 859             @Override                                                                                    
 860             public void run() {                                                                          
 861                 if (hasExtraEmptyScreen()) {                                                             
 862                     mWorkspaceScreens.remove(EXTRA_EMPTY_SCREEN_ID);                                     
 863                     mScreenOrder.remove(EXTRA_EMPTY_SCREEN_ID);                                          
 864                     removeView(cl);                                                                      
 865                     if (stripEmptyScreens) {                                                             
 866                         stripEmptyScreens();                                                             
 867                     }                                                                                    
 868                 }                                                                                        
 869             }                                                                                            
 870         };                                                                                               
 871                                                                                                          
 872         ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(cl, alpha, bgAlpha);                   
 873         oa.setDuration(duration);                                                                        
 874         oa.setStartDelay(delay);                                                                         
 875         oa.addListener(new AnimatorListenerAdapter() {                                                   
 876             @Override                                                                                    
 877             public void onAnimationEnd(Animator animation) {                                             
 878                 if (mRemoveEmptyScreenRunnable != null) {                                                
 879                     mRemoveEmptyScreenRunnable.run();                                                    
 880                 }                                                                                        
 881                 if (onComplete != null) {                                                                
 882                     onComplete.run();                                                                    
 883                 }                                                                                        
 884             }                                                                                            
 885         });                                                                                              
 886         oa.start();                                                                                      
 887     }                                                                                                    
 888                                                                                                          
 889     public boolean hasExtraEmptyScreen() {                                                               
 890         int nScreens = getChildCount();                                                                  
 891         nScreens = nScreens - numCustomPages();                                                          
 892         return mWorkspaceScreens.containsKey(EXTRA_EMPTY_SCREEN_ID) && nScreens > 1;                     
 893     }                                                                                                    
 894                                                                                                          
 895     public long commitExtraEmptyScreen() {                                                               
 896         // Log to disk                                                                                   
 897         Launcher.addDumpLog(TAG, "11683562 - commitExtraEmptyScreen()", true);                           
 898         if (mLauncher.isWorkspaceLoading()) {                                                            
 899             // Invalid and dangerous operation if workspace is loading                                   
 900             Launcher.addDumpLog(TAG, "    - workspace loading, skip", true);                             
 901             return -1;                                                                                   
 902         }                                                                                                
 903         int index = getPageIndexForScreenId(EXTRA_EMPTY_SCREEN_ID);                                      
 904         CellLayout cl = mWorkspaceScreens.get(EXTRA_EMPTY_SCREEN_ID);                                    
 905         mWorkspaceScreens.remove(EXTRA_EMPTY_SCREEN_ID);                                                 
 906         mScreenOrder.remove(EXTRA_EMPTY_SCREEN_ID);                                                      
 907         long newId = LauncherAppState.getLauncherProvider().generateNewScreenId();                       
 908         mWorkspaceScreens.put(newId, cl);                                                                
 909         mScreenOrder.add(newId);                                                                         
 910         // Update the page indicator marker                                                              
 911         if (getPageIndicator() != null) {                                                                
 912             getPageIndicator().updateMarker(index, getPageIndicatorMarker(index));                       
 913         }                                                                                                
 914         // Update the model for the new screen                                                           
 915         mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder);                        
 916         return newId;                                                                                    
 917     }                                                                                                    
 918                                                                                                          
 919     public CellLayout getScreenWithId(long screenId) {                                                   
 920         CellLayout layout = mWorkspaceScreens.get(screenId);                                             
 921         return layout;                                                                                   
 922     }                                                                                                    
 923                                                                                                          
 924     public long getIdForScreen(CellLayout layout) {                                                      
 925         Iterator<Long> iter = mWorkspaceScreens.keySet().iterator();                                     
 926         while (iter.hasNext()) {                                                                         
 927             long id = iter.next();                                                                       
 928             if (mWorkspaceScreens.get(id) == layout) {                                                   
 929                 return id;                                                                               
 930             }                                                                                            
 931         }                                                                                                
 932         return -1;                                                                                       
 933     }                                                                                                    
 934                                                                                                          
 935     public int getPageIndexForScreenId(long screenId) {                                                  
 936         return indexOfChild(mWorkspaceScreens.get(screenId));                                            
 937     }                                                                                                    
 938                                                                                                          
 939     public long getScreenIdForPageIndex(int index) {                                                     
 940         if (0 <= index && index < mScreenOrder.size()) {                                                 
 941             return mScreenOrder.get(index);                                                              
 942         }                                                                                                
 943         return -1;                                                                                       
 944     }                                                                                                    
 945                                                                                                          
 946     ArrayList<Long> getScreenOrder() {                                                                   
 947         return mScreenOrder;                                                                             
 948     }                                                                                                    
 949                                                                                                          
 950     public void stripEmptyScreens() {                                                                    
 951         // Log to disk                                                                                   
 952         Launcher.addDumpLog(TAG, "11683562 - stripEmptyScreens()", true);                                
 953         if (mLauncher.isWorkspaceLoading()) {                                                            
 954             // Don't strip empty screens if the workspace is still loading.                              
 955             // This is dangerous and can result in data loss.                                            
 956             Launcher.addDumpLog(TAG, "    - workspace loading, skip", true);                             
 957             return;                                                                                      
 958         }                                                                                                
 959         if (isPageMoving()) {                                                                            
 960             mStripScreensOnPageStopMoving = true;                                                        
 961             return;                                                                                      
 962         }                                                                                                
 963         int currentPage = getNextPage();                                                                 
 964         ArrayList<Long> removeScreens = new ArrayList<Long>();                                           
 965         for (Long id : mWorkspaceScreens.keySet()) {                                                     
 966             CellLayout cl = mWorkspaceScreens.get(id);                                                   
 967             if ((id >= 0) && (cl.getShortcutsAndWidgets().getChildCount() == 0)) {                       
 968                 removeScreens.add(id);                                                                   
 969             }                                                                                            
 970         }                                                                                                
 971         // We enforce at least one page to add new items to. In the case that we remove the last         
 972         // such screen, we convert the last screen to the empty screen                                   
 973         int minScreens = 1 + numCustomPages();                                                           
 974         int pageShift = 0;                                                                               
 975         for (Long id : removeScreens) {                                                                  
 976             Launcher.addDumpLog(TAG, "11683562 -   removing id: " + id, true);                           
 977             CellLayout cl = mWorkspaceScreens.get(id);                                                   
 978             mWorkspaceScreens.remove(id);                                                                
 979             mScreenOrder.remove(id);                                                                     
 980             if (getChildCount() > minScreens) {                                                          
 981                 if (indexOfChild(cl) < currentPage) {                                                    
 982                     pageShift++;                                                                         
 983                 }                                                                                        
 984                 removeView(cl);                                                                          
 985             } else {                                                                                     
 986                 // if this is the last non-custom content screen, convert it to the empty screen         
 987                 mRemoveEmptyScreenRunnable = null;                                                       
 988                 mWorkspaceScreens.put(EXTRA_EMPTY_SCREEN_ID, cl);                                        
 989                 mScreenOrder.add(EXTRA_EMPTY_SCREEN_ID);                                                 
 990             }                                                                                            
 991         }                                                                                                
 992         if (!removeScreens.isEmpty()) {                                                                  
 993             // Update the model if we have changed any screens                                           
 994             mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder);                    
 995         }                                                                                                
 996         if (pageShift >= 0) {                                                                            
 997             setCurrentPage(currentPage - pageShift);                                                     
 998         }                                                                                                
 999     }                                                                                                    
1000                                                                                                          
1001     // See implementation for parameter definition.                                                      
1002     void addInScreen(View child, long container, long screenId,                                          
1003             int x, int y, int spanX, int spanY) {                                                        
1004         addInScreen(child, container, screenId, x, y, spanX, spanY, false, false);                       
1005     }                                                                                                    
1006                                                                                                          
1007     // At bind time, we use the rank (screenId) to compute x and y for hotseat items.                    
1008     // See implementation for parameter definition.                                                      
1009     void addInScreenFromBind(View child, long container, long screenId, int x, int y,                    
1010             int spanX, int spanY) {                                                                      
1011         addInScreen(child, container, screenId, x, y, spanX, spanY, false, true);                        
1012     }                                                                                                    
1013                                                                                                          
1014     // See implementation for parameter definition.                                                      
1015     void addInScreen(View child, long container, long screenId, int x, int y, int spanX, int spanY,      
1016             boolean insert) {                                                                            
1017         addInScreen(child, container, screenId, x, y, spanX, spanY, insert, false);                      
1018     }                                                                                                    
1019                                                                                                          
1020     /**                                                                                                  
1021      * Adds the specified child in the specified screen. The position and dimension of                   
1022      * the child are defined by x, y, spanX and spanY.                                                   
1023      *                                                                                                   
1024      * @param child The child to add in one of the workspace's screens.                                  
1025      * @param screenId The screen in which to add the child.                                             
1026      * @param x The X position of the child in the screen's grid.                                        
1027      * @param y The Y position of the child in the screen's grid.                                        
1028      * @param spanX The number of cells spanned horizontally by the child.                               
1029      * @param spanY The number of cells spanned vertically by the child.                                 
1030      * @param insert When true, the child is inserted at the beginning of the children list.             
1031      * @param computeXYFromRank When true, we use the rank (stored in screenId) to compute               
1032      *                          the x and y position in which to place hotseat items. Otherwise          
1033      *                          we use the x and y position to compute the rank.                         
1034      */                                                                                                  
1035     void addInScreen(View child, long container, long screenId, int x, int y, int spanX, int spanY, boole🔵
1036         if (container == Favorites.CONTAINER_DESKTOP) {                                                  
1037             if (getScreenWithId(screenId) == null) {                                                     
1038                 Log.e(TAG, ("Skipping child, screenId " + screenId) + " not found");                     
1039                 // DEBUGGING - Print out the stack trace to see where we are adding from                 
1040                 new Throwable().printStackTrace();                                                       
1041                 return;                                                                                  
1042             }                                                                                            
1043         }                                                                                                
1044         if (screenId == EXTRA_EMPTY_SCREEN_ID) {                                                         
1045             // This should never happen                                                                  
1046             throw new RuntimeException("Screen id should not be EXTRA_EMPTY_SCREEN_ID");                 
1047         }                                                                                                
1048         final CellLayout layout;                                                                         
1049         if (container == Favorites.CONTAINER_HOTSEAT) {                                                  
1050             layout = mLauncher.getHotseat().getLayout();                                                 
1051             child.setOnKeyListener(new HotseatIconKeyEventListener());                                   
1052             // Hide folder title in the hotseat                                                          
1053             if (child instanceof FolderIcon) {                                                           
1054                 ((FolderIcon) (child)).setTextVisible(false);                                            
1055             }                                                                                            
1056             if (computeXYFromRank) {                                                                     
1057                 x = mLauncher.getHotseat().getCellXFromOrder(((int) (screenId)));                        
1058                 y = mLauncher.getHotseat().getCellYFromOrder(((int) (screenId)));                        
1059             } else {                                                                                     
1060                 screenId = mLauncher.getHotseat().getOrderInHotseat(x, y);                               
1061             }                                                                                            
1062         } else {                                                                                         
1063             // Show folder title if not in the hotseat                                                   
1064             if (child instanceof FolderIcon) {                                                           
1065                 ((FolderIcon) (child)).setTextVisible(true);                                             
1066             }                                                                                            
1067             layout = getScreenWithId(screenId);                                                          
1068             child.setOnKeyListener(new IconKeyEventListener());                                          
1069         }                                                                                                
1070         ViewGroup.LayoutParams genericLp = child.getLayoutParams();                                      
1071         CellLayout.LayoutParams lp;                                                                      
1072         if ((genericLp == null) || (!(genericLp instanceof CellLayout.LayoutParams))) {                  
1073             lp = new CellLayout.LayoutParams(x, y, spanX, spanY);                                        
1074         } else {                                                                                         
1075             lp = ((CellLayout.LayoutParams) (genericLp));                                                
1076             lp.cellX = x;                                                                                
1077             lp.cellY = y;                                                                                
1078             lp.cellHSpan = spanX;                                                                        
1079             lp.cellVSpan = spanY;                                                                        
1080         }                                                                                                
1081         if ((spanX < 0) && (spanY < 0)) {                                                                
1082             lp.isLockedToGrid = false;                                                                   
1083         }                                                                                                
1084         // Get the canonical child id to uniquely represent this view in this screen                     
1085         ItemInfo info = ((ItemInfo) (child.getTag()));                                                   
1086         int childId = mLauncher.getViewIdForItem(info);                                                  
1087         boolean markCellsAsOccupied = !(child instanceof Folder);                                        
1088         if (!layout.addViewToCellLayout(child, insert ? 0 : -1, childId, lp, markCellsAsOccupied)) {     
1089             // TODO: This branch occurs when the workspace is adding views                               
1090             // outside of the defined grid                                                               
1091             // maybe we should be deleting these items from the LauncherModel?                           
1092             Launcher.addDumpLog(TAG, ((("Failed to add to item at (" + lp.cellX) + ",") + lp.cellY) + ") 🔵
1093         }                                                                                                
1094         if (!(child instanceof Folder)) {                                                                
1095             child.setHapticFeedbackEnabled(false);                                                       
1096             child.setOnLongClickListener(mLongClickListener);                                            
1097         }                                                                                                
1098         if (child instanceof DropTarget) {                                                               
1099             mDragController.addDropTarget(((DropTarget) (child)));                                       
1100         }                                                                                                
1101     }                                                                                                    
1102                                                                                                          
1103     /**                                                                                                  
1104      * Called directly from a CellLayout (not by the framework), after we've been added as a             
1105      * listener via setOnInterceptTouchEventListener(). This allows us to tell the CellLayout            
1106      * that it should intercept touch events, which is not something that is normally supported.         
1107      */                                                                                                  
1108     @Override                                                                                            
1109     public boolean onTouch(View v, MotionEvent event) {                                                  
1110         return (workspaceInModalState() || (!isFinishedSwitchingState())) || ((!workspaceInModalState()) 🔵
1111     }                                                                                                    
1112                                                                                                          
1113     public boolean isSwitchingState() {                                                                  
1114         return mIsSwitchingState;                                                                        
1115     }                                                                                                    
1116                                                                                                          
1117     /** This differs from isSwitchingState in that we take into account how far the transition           
1118      *  has completed. */                                                                                
1119     public boolean isFinishedSwitchingState() {                                                          
1120         return !mIsSwitchingState || (mTransitionProgress > 0.5f);                                       
1121     }                                                                                                    
1122                                                                                                          
1123     protected void onWindowVisibilityChanged (int visibility) {                                          
1124         mLauncher.onWindowVisibilityChanged(visibility);                                                 
1125     }                                                                                                    
1126                                                                                                          
1127     @Override                                                                                            
1128     public boolean dispatchUnhandledMove(View focused, int direction) {                                  
1129         if (workspaceInModalState() || (!isFinishedSwitchingState())) {                                  
1130             // when the home screens are shrunken, shouldn't allow side-scrolling                        
1131             return false;                                                                                
1132         }                                                                                                
1133         return super.dispatchUnhandledMove(focused, direction);                                          
1134     }                                                                                                    
1135                                                                                                          
1136     @Override                                                                                            
1137     public boolean onInterceptTouchEvent(MotionEvent ev) {                                               
1138         switch (ev.getAction() & MotionEvent.ACTION_MASK) {                                              
1139             case MotionEvent.ACTION_DOWN :                                                               
1140                 mXDown = ev.getX();                                                                      
1141                 mYDown = ev.getY();                                                                      
1142                 mTouchDownTime = System.currentTimeMillis();                                             
1143                 break;                                                                                   
1144             case MotionEvent.ACTION_POINTER_UP :                                                         
1145             case MotionEvent.ACTION_UP :                                                                 
1146                 if (mTouchState == TOUCH_STATE_REST) {                                                   
1147                     final CellLayout currentPage = ((CellLayout) (getChildAt(mCurrentPage)));            
1148                     if ((currentPage != null) && (!currentPage.lastDownOnOccupiedCell())) {              
1149                         onWallpaperTap(ev);                                                              
1150                     }                                                                                    
1151                 }                                                                                        
1152         }                                                                                                
1153         return super.onInterceptTouchEvent(ev);                                                          
1154     }                                                                                                    
1155                                                                                                          
1156     @Override                                                                                            
1157     public boolean onGenericMotionEvent(MotionEvent event) {                                             
1158         // Ignore pointer scroll events if the custom content doesn't allow scrolling.                   
1159         if (((getScreenIdForPageIndex(getCurrentPage()) == CUSTOM_CONTENT_SCREEN_ID) && (mCustomContentCa🔵
1160             return false;                                                                                
1161         }                                                                                                
1162         return super.onGenericMotionEvent(event);                                                        
1163     }                                                                                                    
1164                                                                                                          
1165     protected void reinflateWidgetsIfNecessary() {                                                       
1166         final int clCount = getChildCount();                                                             
1167         for (int i = 0; i < clCount; i++) {                                                              
1168             CellLayout cl = ((CellLayout) (getChildAt(i)));                                              
1169             ShortcutAndWidgetContainer swc = cl.getShortcutsAndWidgets();                                
1170             final int itemCount = swc.getChildCount();                                                   
1171             for (int j = 0; j < itemCount; j++) {                                                        
1172                 View v = swc.getChildAt(j);                                                              
1173                 if ((v != null) && (v.getTag() instanceof LauncherAppWidgetInfo)) {                      
1174                     LauncherAppWidgetInfo info = ((LauncherAppWidgetInfo) (v.getTag()));                 
1175                     LauncherAppWidgetHostView lahv = ((LauncherAppWidgetHostView) (info.hostView));      
1176                     if ((lahv != null) && lahv.isReinflateRequired()) {                                  
1177                         mLauncher.removeAppWidget(info);                                                 
1178                         // Remove the current widget which is inflated with the wrong orientation        
1179                         cl.removeView(lahv);                                                             
1180                         mLauncher.bindAppWidget(info);                                                   
1181                     }                                                                                    
1182                 }                                                                                        
1183             }                                                                                            
1184         }                                                                                                
1185     }                                                                                                    
1186                                                                                                          
1187     @Override                                                                                            
1188     protected void determineScrollingStart(MotionEvent ev) {                                             
1189         if (!isFinishedSwitchingState()) {                                                               
1190             return;                                                                                      
1191         }                                                                                                
1192         float deltaX = ev.getX() - mXDown;                                                               
1193         float absDeltaX = Math.abs(deltaX);                                                              
1194         float absDeltaY = Math.abs(ev.getY() - mYDown);                                                  
1195         if (Float.compare(absDeltaX, 0.0F) == 0) {                                                       
1196             return;                                                                                      
1197         }                                                                                                
1198         float slope = absDeltaY / absDeltaX;                                                             
1199         float theta = ((float) (Math.atan(slope)));                                                      
1200         if ((absDeltaX > mTouchSlop) || (absDeltaY > mTouchSlop)) {                                      
1201             cancelCurrentPageLongPress();                                                                
1202         }                                                                                                
1203         boolean passRightSwipesToCustomContent = (mTouchDownTime - mCustomContentShowTime) > CUSTOM_CONTE🔵
1204         boolean swipeInIgnoreDirection = (isLayoutRtl()) ? deltaX < 0 : deltaX > 0;                      
1205         boolean onCustomContentScreen = getScreenIdForPageIndex(getCurrentPage()) == CUSTOM_CONTENT_SCREE🔵
1206         if ((swipeInIgnoreDirection && onCustomContentScreen) && passRightSwipesToCustomContent) {       
1207             // Pass swipes to the right to the custom content page.                                      
1208             return;                                                                                      
1209         }                                                                                                
1210         if ((onCustomContentScreen && (mCustomContentCallbacks != null)) && (!mCustomContentCallbacks.isS🔵
1211             // Don't allow workspace scrolling if the current custom content screen doesn't allow        
1212             // scrolling.                                                                                
1213             return;                                                                                      
1214         }                                                                                                
1215         if (theta > MAX_SWIPE_ANGLE) {                                                                   
1216             // Above MAX_SWIPE_ANGLE, we don't want to ever start scrolling the workspace                
1217             return;                                                                                      
1218         } else if (theta > START_DAMPING_TOUCH_SLOP_ANGLE) {                                             
1219             // Above START_DAMPING_TOUCH_SLOP_ANGLE and below MAX_SWIPE_ANGLE, we want to                
1220             // increase the touch slop to make it harder to begin scrolling the workspace. This          
1221             // results in vertically scrolling widgets to more easily. The higher the angle, the         
1222             // more we increase touch slop.                                                              
1223             theta -= START_DAMPING_TOUCH_SLOP_ANGLE;                                                     
1224             float extraRatio = ((float) (Math.sqrt(theta / (MAX_SWIPE_ANGLE - START_DAMPING_TOUCH_SLOP_AN🔵
1225             super.determineScrollingStart(ev, 1 + (TOUCH_SLOP_DAMPING_FACTOR * extraRatio));             
1226         } else {                                                                                         
1227             // Below START_DAMPING_TOUCH_SLOP_ANGLE, we don't do anything special                        
1228             super.determineScrollingStart(ev);                                                           
1229         }                                                                                                
1230     }                                                                                                    
1231                                                                                                          
1232     protected void onPageBeginMoving() {                                                                 
1233         super.onPageBeginMoving();                                                                       
1234         if (isHardwareAccelerated()) {                                                                   
1235             updateChildrenLayersEnabled(false);                                                          
1236         } else if (mNextPage != INVALID_PAGE) {                                                          
1237             // we're snapping to a particular screen                                                     
1238             enableChildrenCache(mCurrentPage, mNextPage);                                                
1239         } else {                                                                                         
1240             // this is when user is actively dragging a particular screen, they might                    
1241             // swipe it either left or right (but we won't advance by more than one screen)              
1242             enableChildrenCache(mCurrentPage - 1, mCurrentPage + 1);                                     
1243         }                                                                                                
1244     }                                                                                                    
1245                                                                                                          
1246     protected void onPageEndMoving() {                                                                   
1247         super.onPageEndMoving();                                                                         
1248         if (isHardwareAccelerated()) {                                                                   
1249             updateChildrenLayersEnabled(false);                                                          
1250         } else {                                                                                         
1251             clearChildrenCache();                                                                        
1252         }                                                                                                
1253         if (mDragController.isDragging()) {                                                              
1254             if (workspaceInModalState()) {                                                               
1255                 // If we are in springloaded mode, then force an event to check if the current touch     
1256                 // is under a new page (to scroll to)                                                    
1257                 mDragController.forceTouchMove();                                                        
1258             }                                                                                            
1259         }                                                                                                
1260         if (mDelayedResizeRunnable != null) {                                                            
1261             mDelayedResizeRunnable.run();                                                                
1262             mDelayedResizeRunnable = null;                                                               
1263         }                                                                                                
1264         if (mDelayedSnapToPageRunnable != null) {                                                        
1265             mDelayedSnapToPageRunnable.run();                                                            
1266             mDelayedSnapToPageRunnable = null;                                                           
1267         }                                                                                                
1268         if (mStripScreensOnPageStopMoving) {                                                             
1269             stripEmptyScreens();                                                                         
1270             mStripScreensOnPageStopMoving = false;                                                       
1271         }                                                                                                
1272     }                                                                                                    
1273                                                                                                          
1274     @Override                                                                                            
1275     protected void notifyPageSwitchListener() {                                                          
1276         super.notifyPageSwitchListener();                                                                
1277         Launcher.setScreen(getNextPage());                                                               
1278         if ((hasCustomContent() && (getNextPage() == 0)) && (!mCustomContentShowing)) {                  
1279             mCustomContentShowing = true;                                                                
1280             if (mCustomContentCallbacks != null) {                                                       
1281                 mCustomContentCallbacks.onShow(false);                                                   
1282                 mCustomContentShowTime = System.currentTimeMillis();                                     
1283                 mLauncher.updateVoiceButtonProxyVisible(false);                                          
1284             }                                                                                            
1285         } else if ((hasCustomContent() && (getNextPage() != 0)) && mCustomContentShowing) {              
1286             mCustomContentShowing = false;                                                               
1287             if (mCustomContentCallbacks != null) {                                                       
1288                 mCustomContentCallbacks.onHide();                                                        
1289                 mLauncher.resetQSBScroll();                                                              
1290                 mLauncher.updateVoiceButtonProxyVisible(false);                                          
1291             }                                                                                            
1292         }                                                                                                
1293     }                                                                                                    
1294                                                                                                          
1295     protected CustomContentCallbacks getCustomContentCallbacks() {                                       
1296         return mCustomContentCallbacks;                                                                  
1297     }                                                                                                    
1298                                                                                                          
1299     protected void setWallpaperDimension() {                                                             
1300         new AsyncTask<Void, Void, Void>() {                                                              
1301             public Void doInBackground(Void... args) {                                                   
1302                 String spKey = WallpaperCropActivity.getSharedPreferencesKey();                          
1303                 SharedPreferences sp = mLauncher.getSharedPreferences(spKey, Context.MODE_MULTI_PROCESS);
1304                 LauncherWallpaperPickerActivity.suggestWallpaperDimension(mLauncher.getResources(), sp, m🔵
1305                 return null;                                                                             
1306             }                                                                                            
1307         }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, ((Void) (null)));                            
1308     }                                                                                                    
1309                                                                                                          
1310     protected void snapToPage(int whichPage, Runnable r) {                                               
1311         snapToPage(whichPage, SLOW_PAGE_SNAP_ANIMATION_DURATION, r);                                     
1312     }                                                                                                    
1313                                                                                                          
1314     protected void snapToPage(int whichPage, int duration, Runnable r) {                                 
1315         if (mDelayedSnapToPageRunnable != null) {                                                        
1316             mDelayedSnapToPageRunnable.run();                                                            
1317         }                                                                                                
1318         mDelayedSnapToPageRunnable = r;                                                                  
1319         snapToPage(whichPage, duration);                                                                 
1320     }                                                                                                    
1321                                                                                                          
1322     public void snapToScreenId(long screenId) {                                                          
1323         snapToScreenId(screenId, null);                                                                  
1324     }                                                                                                    
1325                                                                                                          
1326     protected void snapToScreenId(long screenId, Runnable r) {                                           
1327         snapToPage(getPageIndexForScreenId(screenId), r);                                                
1328     }                                                                                                    
1329                                                                                                          
1330     class WallpaperOffsetInterpolator implements Choreographer.FrameCallback {                           
1331         float mFinalOffset = 0.0F;                                                                       
1332                                                                                                          
1333         float mCurrentOffset = 0.5F;// to force an initial update                                        
1334                                                                                                          
1335                                                                                                          
1336         boolean mWaitingForUpdate;                                                                       
1337                                                                                                          
1338         Choreographer mChoreographer;                                                                    
1339                                                                                                          
1340         Interpolator mInterpolator;                                                                      
1341                                                                                                          
1342         boolean mAnimating;                                                                              
1343                                                                                                          
1344         long mAnimationStartTime;                                                                        
1345                                                                                                          
1346         float mAnimationStartOffset;                                                                     
1347                                                                                                          
1348         private final int ANIMATION_DURATION = 250;                                                      
1349                                                                                                          
1350         // Don't use all the wallpaper for parallax until you have at least this many pages              
1351         private final int MIN_PARALLAX_PAGE_SPAN = 3;                                                    
1352                                                                                                          
1353         int mNumScreens;                                                                                 
1354                                                                                                          
1355         public WallpaperOffsetInterpolator() {                                                           
1356             mChoreographer = Choreographer.getInstance();                                                
1357             mInterpolator = new DecelerateInterpolator(1.5F);                                            
1358         }                                                                                                
1359                                                                                                          
1360         @Override                                                                                        
1361         public void doFrame(long frameTimeNanos) {                                                       
1362             updateOffset(false);                                                                         
1363         }                                                                                                
1364                                                                                                          
1365         private void updateOffset(boolean force) {                                                       
1366             if (mWaitingForUpdate || force) {                                                            
1367                 mWaitingForUpdate = false;                                                               
1368                 if (computeScrollOffset() && (mWindowToken != null)) {                                   
1369                     try {                                                                                
1370                         mWallpaperManager.setWallpaperOffsets(mWindowToken, mWallpaperOffset.getCurrX(), 🔵
1371                         setWallpaperOffsetSteps();                                                       
1372                     } catch (java.lang.IllegalArgumentException e) {                                     
1373                         Log.e(TAG, "Error updating wallpaper offset: " + e);                             
1374                     }                                                                                    
1375                 }                                                                                        
1376             }                                                                                            
1377         }                                                                                                
1378                                                                                                          
1379         public boolean computeScrollOffset() {                                                           
1380             final float oldOffset = mCurrentOffset;                                                      
1381             if (mAnimating) {                                                                            
1382                 long durationSinceAnimation = System.currentTimeMillis() - mAnimationStartTime;          
1383                 float t0 = durationSinceAnimation / ((float) (ANIMATION_DURATION));                      
1384                 float t1 = mInterpolator.getInterpolation(t0);                                           
1385                 mCurrentOffset = mAnimationStartOffset + ((mFinalOffset - mAnimationStartOffset) * t1);  
1386                 mAnimating = durationSinceAnimation < ANIMATION_DURATION;                                
1387             } else {                                                                                     
1388                 mCurrentOffset = mFinalOffset;                                                           
1389             }                                                                                            
1390             if (Math.abs(mCurrentOffset - mFinalOffset) > 1.0E-7F) {                                     
1391                 scheduleUpdate();                                                                        
1392             }                                                                                            
1393             if (Math.abs(oldOffset - mCurrentOffset) > 1.0E-7F) {                                        
1394                 return true;                                                                             
1395             }                                                                                            
1396             return false;                                                                                
1397         }                                                                                                
1398                                                                                                          
1399         private float wallpaperOffsetForCurrentScroll() {                                                
1400             if (getChildCount() <= 1) {                                                                  
1401                 return 0;                                                                                
1402             }                                                                                            
1403             // Exclude the leftmost page                                                                 
1404             int emptyExtraPages = numEmptyScreensToIgnore();                                             
1405             int firstIndex = numCustomPages();                                                           
1406             // Exclude the last extra empty screen (if we have > MIN_PARALLAX_PAGE_SPAN pages)           
1407             int lastIndex = (getChildCount() - 1) - emptyExtraPages;                                     
1408             if (isLayoutRtl()) {                                                                         
1409                 int temp = firstIndex;                                                                   
1410                 firstIndex = lastIndex;                                                                  
1411                 lastIndex = temp;                                                                        
1412             }                                                                                            
1413             int firstPageScrollX = getScrollForPage(firstIndex);                                         
1414             int scrollRange = getScrollForPage(lastIndex) - firstPageScrollX;                            
1415             if (scrollRange == 0) {                                                                      
1416                 return 0;                                                                                
1417             } else {                                                                                     
1418                 // TODO: do different behavior if it's  a live wallpaper?                                
1419                 // Sometimes the left parameter of the pages is animated during a layout transition;     
1420                 // this parameter offsets it to keep the wallpaper from animating as well                
1421                 int adjustedScroll = (getScrollX() - firstPageScrollX) - getLayoutTransitionOffsetForPage🔵
1422                 float offset = Math.min(1, adjustedScroll / ((float) (scrollRange)));                    
1423                 offset = Math.max(0, offset);                                                            
1424                 // Don't use up all the wallpaper parallax until you have at least                       
1425                 // MIN_PARALLAX_PAGE_SPAN pages                                                          
1426                 int numScrollingPages = getNumScreensExcludingEmptyAndCustom();                          
1427                 int parallaxPageSpan;                                                                    
1428                 if (mWallpaperIsLiveWallpaper) {                                                         
1429                     parallaxPageSpan = numScrollingPages - 1;                                            
1430                 } else {                                                                                 
1431                     parallaxPageSpan = Math.max(MIN_PARALLAX_PAGE_SPAN, numScrollingPages - 1);          
1432                 }                                                                                        
1433                 mNumPagesForWallpaperParallax = parallaxPageSpan;                                        
1434                 // On RTL devices, push the wallpaper offset to the right if we don't have enough        
1435                 // pages (ie if numScrollingPages < MIN_PARALLAX_PAGE_SPAN)                              
1436                 int padding = (isLayoutRtl()) ? (parallaxPageSpan - numScrollingPages) + 1 : 0;          
1437                 return (offset * ((padding + numScrollingPages) - 1)) / parallaxPageSpan;                
1438             }                                                                                            
1439         }                                                                                                
1440                                                                                                          
1441         private int numEmptyScreensToIgnore() {                                                          
1442             int numScrollingPages = getChildCount() - numCustomPages();                                  
1443             if ((numScrollingPages >= MIN_PARALLAX_PAGE_SPAN) && hasExtraEmptyScreen()) {                
1444                 return 1;                                                                                
1445             } else {                                                                                     
1446                 return 0;                                                                                
1447             }                                                                                            
1448         }                                                                                                
1449                                                                                                          
1450         private int getNumScreensExcludingEmptyAndCustom() {                                             
1451             int numScrollingPages = (getChildCount() - numEmptyScreensToIgnore()) - numCustomPages();    
1452             return numScrollingPages;                                                                    
1453         }                                                                                                
1454                                                                                                          
1455         public void syncWithScroll() {                                                                   
1456             float offset = wallpaperOffsetForCurrentScroll();                                            
1457             mWallpaperOffset.setFinalX(offset);                                                          
1458             updateOffset(true);                                                                          
1459         }                                                                                                
1460                                                                                                          
1461         public float getCurrX() {                                                                        
1462             return mCurrentOffset;                                                                       
1463         }                                                                                                
1464                                                                                                          
1465         public float getFinalX() {                                                                       
1466             return mFinalOffset;                                                                         
1467         }                                                                                                
1468                                                                                                          
1469         private void animateToFinal() {                                                                  
1470             mAnimating = true;                                                                           
1471             mAnimationStartOffset = mCurrentOffset;                                                      
1472             mAnimationStartTime = System.currentTimeMillis();                                            
1473         }                                                                                                
1474                                                                                                          
1475         private void setWallpaperOffsetSteps() {                                                         
1476             // Set wallpaper offset steps (1 / (number of screens - 1))                                  
1477             float xOffset = 1.0F / mNumPagesForWallpaperParallax;                                        
1478             if (xOffset != mLastSetWallpaperOffsetSteps) {                                               
1479                 mWallpaperManager.setWallpaperOffsetSteps(xOffset, 1.0F);                                
1480                 mLastSetWallpaperOffsetSteps = xOffset;                                                  
1481             }                                                                                            
1482         }                                                                                                
1483                                                                                                          
1484         public void setFinalX(float x) {                                                                 
1485             scheduleUpdate();                                                                            
1486             mFinalOffset = Math.max(0.0F, Math.min(x, 1.0F));                                            
1487             if (getNumScreensExcludingEmptyAndCustom() != mNumScreens) {                                 
1488                 if (mNumScreens > 0) {                                                                   
1489                     // Don't animate if we're going from 0 screens                                       
1490                     animateToFinal();                                                                    
1491                 }                                                                                        
1492                 mNumScreens = getNumScreensExcludingEmptyAndCustom();                                    
1493             }                                                                                            
1494         }                                                                                                
1495                                                                                                          
1496         private void scheduleUpdate() {                                                                  
1497             if (!mWaitingForUpdate) {                                                                    
1498                 mChoreographer.postFrameCallback(this);                                                  
1499                 mWaitingForUpdate = true;                                                                
1500             }                                                                                            
1501         }                                                                                                
1502                                                                                                          
1503         public void jumpToFinal() {                                                                      
1504             mCurrentOffset = mFinalOffset;                                                               
1505         }                                                                                                
1506     }                                                                                                    
1507                                                                                                          
1508     @Override                                                                                            
1509     public void computeScroll() {                                                                        
1510         super.computeScroll();                                                                           
1511         mWallpaperOffset.syncWithScroll();                                                               
1512     }                                                                                                    
1513                                                                                                          
1514     @Override                                                                                            
1515     public void announceForAccessibility(CharSequence text) {                                            
1516         // Don't announce if apps is on top of us.                                                       
1517         if (!mLauncher.isAllAppsVisible()) {                                                             
1518             super.announceForAccessibility(text);                                                        
1519         }                                                                                                
1520     }                                                                                                    
1521                                                                                                          
1522     void showOutlines() {                                                                                
1523         if ((!workspaceInModalState()) && (!mIsSwitchingState)) {                                        
1524             if (mChildrenOutlineFadeOutAnimation != null) {                                              
1525                 mChildrenOutlineFadeOutAnimation.cancel();                                               
1526             }                                                                                            
1527             if (mChildrenOutlineFadeInAnimation != null) {                                               
1528                 mChildrenOutlineFadeInAnimation.cancel();                                                
1529             }                                                                                            
1530             mChildrenOutlineFadeInAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 1.0🔵
1531             mChildrenOutlineFadeInAnimation.setDuration(CHILDREN_OUTLINE_FADE_IN_DURATION);              
1532             mChildrenOutlineFadeInAnimation.start();                                                     
1533         }                                                                                                
1534     }                                                                                                    
1535                                                                                                          
1536     void hideOutlines() {                                                                                
1537         if ((!workspaceInModalState()) && (!mIsSwitchingState)) {                                        
1538             if (mChildrenOutlineFadeInAnimation != null) {                                               
1539                 mChildrenOutlineFadeInAnimation.cancel();                                                
1540             }                                                                                            
1541             if (mChildrenOutlineFadeOutAnimation != null) {                                              
1542                 mChildrenOutlineFadeOutAnimation.cancel();                                               
1543             }                                                                                            
1544             mChildrenOutlineFadeOutAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 0.🔵
1545             mChildrenOutlineFadeOutAnimation.setDuration(CHILDREN_OUTLINE_FADE_OUT_DURATION);            
1546             mChildrenOutlineFadeOutAnimation.setStartDelay(CHILDREN_OUTLINE_FADE_OUT_DELAY);             
1547             mChildrenOutlineFadeOutAnimation.start();                                                    
1548         }                                                                                                
1549     }                                                                                                    
1550                                                                                                          
1551     public void showOutlinesTemporarily() {                                                              
1552         if (!mIsPageMoving && !isTouchActive()) {                                                        
1553             snapToPage(mCurrentPage);                                                                    
1554         }                                                                                                
1555     }                                                                                                    
1556                                                                                                          
1557     public void setChildrenOutlineAlpha(float alpha) {                                                   
1558         mChildrenOutlineAlpha = alpha;                                                                   
1559         for (int i = 0; i < getChildCount(); i++) {                                                      
1560             CellLayout cl = (CellLayout) getChildAt(i);                                                  
1561             cl.setBackgroundAlpha(alpha);                                                                
1562         }                                                                                                
1563     }                                                                                                    
1564                                                                                                          
1565     public float getChildrenOutlineAlpha() {                                                             
1566         return mChildrenOutlineAlpha;                                                                    
1567     }                                                                                                    
1568                                                                                                          
1569     private void animateBackgroundGradient(float finalAlpha, boolean animated) {                         
1570         final DragLayer dragLayer = mLauncher.getDragLayer();                                            
1571         if (mBackgroundFadeInAnimation != null) {                                                        
1572             mBackgroundFadeInAnimation.cancel();                                                         
1573             mBackgroundFadeInAnimation = null;                                                           
1574         }                                                                                                
1575         if (mBackgroundFadeOutAnimation != null) {                                                       
1576             mBackgroundFadeOutAnimation.cancel();                                                        
1577             mBackgroundFadeOutAnimation = null;                                                          
1578         }                                                                                                
1579         float startAlpha = dragLayer.getBackgroundAlpha();                                               
1580         if (finalAlpha != startAlpha) {                                                                  
1581             if (animated) {                                                                              
1582                 mBackgroundFadeOutAnimation = LauncherAnimUtils.ofFloat(this, startAlpha, finalAlpha);   
1583                 mBackgroundFadeOutAnimation.addUpdateListener(new AnimatorUpdateListener() {             
1584                     public void onAnimationUpdate(ValueAnimator animation) {                             
1585                         dragLayer.setBackgroundAlpha(((Float) (animation.getAnimatedValue())).floatValue(🔵
1586                     }                                                                                    
1587                 });                                                                                      
1588                 mBackgroundFadeOutAnimation.setInterpolator(new DecelerateInterpolator(1.5F));           
1589                 mBackgroundFadeOutAnimation.setDuration(BACKGROUND_FADE_OUT_DURATION);                   
1590                 mBackgroundFadeOutAnimation.start();                                                     
1591             } else {                                                                                     
1592                 dragLayer.setBackgroundAlpha(finalAlpha);                                                
1593             }                                                                                            
1594         }                                                                                                
1595     }                                                                                                    
1596                                                                                                          
1597     float backgroundAlphaInterpolator(float r) {                                                         
1598         float pivotA = 0.1f;                                                                             
1599         float pivotB = 0.4f;                                                                             
1600         if (r < pivotA) {                                                                                
1601             return 0;                                                                                    
1602         } else if (r > pivotB) {                                                                         
1603             return 1.0f;                                                                                 
1604         } else {                                                                                         
1605             return (r - pivotA)/(pivotB - pivotA);                                                       
1606         }                                                                                                
1607     }                                                                                                    
1608                                                                                                          
1609     private void updatePageAlphaValues(int screenCenter) {                                               
1610         boolean isInOverscroll = (mOverScrollX < 0) || (mOverScrollX > mMaxScrollX);                     
1611         if (((mWorkspaceFadeInAdjacentScreens && (!workspaceInModalState())) && (!mIsSwitchingState)) && 🔵
1612             for (int i = numCustomPages(); i < getChildCount(); i++) {                                   
1613                 CellLayout child = ((CellLayout) (getChildAt(i)));                                       
1614                 if (child != null) {                                                                     
1615                     float scrollProgress = getScrollProgress(screenCenter, child, i);                    
1616                     float alpha = 1 - Math.abs(scrollProgress);                                          
1617                     child.getShortcutsAndWidgets().setAlpha(alpha);                                      
1618                     //child.setBackgroundAlphaMultiplier(1 - alpha);                                     
1619                 }                                                                                        
1620             }                                                                                            
1621         }                                                                                                
1622     }                                                                                                    
1623                                                                                                          
1624     private void setChildrenBackgroundAlphaMultipliers(float a) {                                        
1625         for (int i = 0; i < getChildCount(); i++) {                                                      
1626             CellLayout child = (CellLayout) getChildAt(i);                                               
1627             child.setBackgroundAlphaMultiplier(a);                                                       
1628         }                                                                                                
1629     }                                                                                                    
1630                                                                                                          
1631     public boolean hasCustomContent() {                                                                  
1632         return (mScreenOrder.size() > 0 && mScreenOrder.get(0) == CUSTOM_CONTENT_SCREEN_ID);             
1633     }                                                                                                    
1634                                                                                                          
1635     public int numCustomPages() {                                                                        
1636         return hasCustomContent() ? 1 : 0;                                                               
1637     }                                                                                                    
1638                                                                                                          
1639     public boolean isOnOrMovingToCustomContent() {                                                       
1640         return hasCustomContent() && getNextPage() == 0;                                                 
1641     }                                                                                                    
1642                                                                                                          
1643     private void updateStateForCustomContent(int screenCenter) {                                         
1644         float translationX = 0;                                                                          
1645         float progress = 0;                                                                              
1646         if (hasCustomContent()) {                                                                        
1647             int index = mScreenOrder.indexOf(CUSTOM_CONTENT_SCREEN_ID);                                  
1648             int scrollDelta = (getScrollX() - getScrollForPage(index)) - getLayoutTransitionOffsetForPage🔵
1649             float scrollRange = getScrollForPage(index + 1) - getScrollForPage(index);                   
1650             translationX = scrollRange - scrollDelta;                                                    
1651             progress = (scrollRange - scrollDelta) / scrollRange;                                        
1652             if (isLayoutRtl()) {                                                                         
1653                 translationX = Math.min(0, translationX);                                                
1654             } else {                                                                                     
1655                 translationX = Math.max(0, translationX);                                                
1656             }                                                                                            
1657             progress = Math.max(0, progress);                                                            
1658         }                                                                                                
1659         if (Float.compare(progress, mLastCustomContentScrollProgress) == 0) {                            
1660             return;                                                                                      
1661         }                                                                                                
1662         CellLayout cc = mWorkspaceScreens.get(CUSTOM_CONTENT_SCREEN_ID);                                 
1663         if (((progress > 0) && (cc.getVisibility() != VISIBLE)) && (!workspaceInModalState())) {         
1664             cc.setVisibility(VISIBLE);                                                                   
1665         }                                                                                                
1666         mLastCustomContentScrollProgress = progress;                                                     
1667         mLauncher.getDragLayer().setBackgroundAlpha(progress * 0.8F);                                    
1668         if (mLauncher.getHotseat() != null) {                                                            
1669             mLauncher.getHotseat().setTranslationX(translationX);                                        
1670         }                                                                                                
1671         if (getPageIndicator() != null) {                                                                
1672             getPageIndicator().setTranslationX(translationX);                                            
1673         }                                                                                                
1674         if (mCustomContentCallbacks != null) {                                                           
1675             mCustomContentCallbacks.onScrollProgressChanged(progress);                                   
1676         }                                                                                                
1677     }                                                                                                    
1678                                                                                                          
1679     @Override                                                                                            
1680     protected OnClickListener getPageIndicatorClickListener() {                                          
1681         AccessibilityManager am = (AccessibilityManager)                                                 
1682                 getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);                            
1683         if (!am.isTouchExplorationEnabled()) {                                                           
1684             return null;                                                                                 
1685         }                                                                                                
1686         OnClickListener listener = new OnClickListener() {                                               
1687             @Override                                                                                    
1688             public void onClick(View arg0) {                                                             
1689                 enterOverviewMode();                                                                     
1690             }                                                                                            
1691         };                                                                                               
1692         return listener;                                                                                 
1693     }                                                                                                    
1694                                                                                                          
1695     @Override                                                                                            
1696     protected void screenScrolled(int screenCenter) {                                                    
1697         final boolean isRtl = isLayoutRtl();                                                             
1698         super.screenScrolled(screenCenter);                                                              
1699         updatePageAlphaValues(screenCenter);                                                             
1700         updateStateForCustomContent(screenCenter);                                                       
1701         enableHwLayersOnVisiblePages();                                                                  
1702         boolean shouldOverScroll = (mOverScrollX < 0) || (mOverScrollX > mMaxScrollX);                   
1703         if (shouldOverScroll) {                                                                          
1704             int index = 0;                                                                               
1705             final int lowerIndex = 0;                                                                    
1706             final int upperIndex = getChildCount() - 1;                                                  
1707             final boolean isLeftPage = mOverScrollX < 0;                                                 
1708             index = (((!isRtl) && isLeftPage) || (isRtl && (!isLeftPage))) ? lowerIndex : upperIndex;    
1709             CellLayout cl = ((CellLayout) (getChildAt(index)));                                          
1710             float effect = Math.abs(mOverScrollEffect);                                                  
1711             cl.setOverScrollAmount(Math.abs(effect), isLeftPage);                                        
1712             mOverscrollEffectSet = true;                                                                 
1713         } else if (mOverscrollEffectSet && (getChildCount() > 0)) {                                      
1714             mOverscrollEffectSet = false;                                                                
1715             ((CellLayout) (getChildAt(0))).setOverScrollAmount(0, false);                                
1716             ((CellLayout) (getChildAt(getChildCount() - 1))).setOverScrollAmount(0, false);              
1717         }                                                                                                
1718     }                                                                                                    
1719                                                                                                          
1720     @Override                                                                                            
1721     protected void overScroll(float amount) {                                                            
1722         boolean shouldOverScroll = ((amount < 0) && ((!hasCustomContent()) || isLayoutRtl())) || ((amount🔵
1723         if (shouldOverScroll) {                                                                          
1724             dampedOverScroll(amount);                                                                    
1725             mOverScrollEffect = acceleratedOverFactor(amount);                                           
1726         } else {                                                                                         
1727             mOverScrollEffect = 0;                                                                       
1728         }                                                                                                
1729     }                                                                                                    
1730                                                                                                          
1731     protected void onAttachedToWindow() {                                                                
1732         super.onAttachedToWindow();                                                                      
1733         mWindowToken = getWindowToken();                                                                 
1734         computeScroll();                                                                                 
1735         mDragController.setWindowToken(mWindowToken);                                                    
1736     }                                                                                                    
1737                                                                                                          
1738     protected void onDetachedFromWindow() {                                                              
1739         super.onDetachedFromWindow();                                                                    
1740         mWindowToken = null;                                                                             
1741     }                                                                                                    
1742                                                                                                          
1743     protected void onResume() {                                                                          
1744         if (getPageIndicator() != null) {                                                                
1745             // In case accessibility state has changed, we need to perform this on every                 
1746             // attach to window                                                                          
1747             OnClickListener listener = getPageIndicatorClickListener();                                  
1748             if (listener != null) {                                                                      
1749                 getPageIndicator().setOnClickListener(listener);                                         
1750             }                                                                                            
1751         }                                                                                                
1752         AccessibilityManager am = (AccessibilityManager)                                                 
1753                 getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);                            
1754         sAccessibilityEnabled = am.isEnabled();                                                          
1755                                                                                                          
1756         // Update wallpaper dimensions if they were changed since last onResume                          
1757         // (we also always set the wallpaper dimensions in the constructor)                              
1758         if (LauncherAppState.getInstance().hasWallpaperChangedSinceLastCheck()) {                        
1759             setWallpaperDimension();                                                                     
1760         }                                                                                                
1761         mWallpaperIsLiveWallpaper = mWallpaperManager.getWallpaperInfo() != null;                        
1762         // Force the wallpaper offset steps to be set again, because another app might have changed      
1763         // them                                                                                          
1764         mLastSetWallpaperOffsetSteps = 0f;                                                               
1765     }                                                                                                    
1766                                                                                                          
1767     @Override                                                                                            
1768     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {                 
1769         if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) {                       
1770             mWallpaperOffset.syncWithScroll();                                                           
1771             mWallpaperOffset.jumpToFinal();                                                              
1772         }                                                                                                
1773         super.onLayout(changed, left, top, right, bottom);                                               
1774     }                                                                                                    
1775                                                                                                          
1776     @Override                                                                                            
1777     protected void onDraw(Canvas canvas) {                                                               
1778         super.onDraw(canvas);                                                                            
1779         // Call back to LauncherModel to finish binding after the first draw                             
1780         post(mBindPages);                                                                                
1781     }                                                                                                    
1782                                                                                                          
1783     @Override                                                                                            
1784     protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {           
1785         if (!mLauncher.isAllAppsVisible()) {                                                             
1786             final Folder openFolder = getOpenFolder();                                                   
1787             if (openFolder != null) {                                                                    
1788                 return openFolder.requestFocus(direction, previouslyFocusedRect);                        
1789             } else {                                                                                     
1790                 return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);              
1791             }                                                                                            
1792         }                                                                                                
1793         return false;                                                                                    
1794     }                                                                                                    
1795                                                                                                          
1796     @Override                                                                                            
1797     public int getDescendantFocusability() {                                                             
1798         if (workspaceInModalState()) {                                                                   
1799             return ViewGroup.FOCUS_BLOCK_DESCENDANTS;                                                    
1800         }                                                                                                
1801         return super.getDescendantFocusability();                                                        
1802     }                                                                                                    
1803                                                                                                          
1804     @Override                                                                                            
1805     public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {                 
1806         if (!mLauncher.isAllAppsVisible()) {                                                             
1807             final Folder openFolder = getOpenFolder();                                                   
1808             if (openFolder != null) {                                                                    
1809                 openFolder.addFocusables(views, direction);                                              
1810             } else {                                                                                     
1811                 super.addFocusables(views, direction, focusableMode);                                    
1812             }                                                                                            
1813         }                                                                                                
1814     }                                                                                                    
1815                                                                                                          
1816     public boolean workspaceInModalState() {                                                             
1817         return mState != State.NORMAL;                                                                   
1818     }                                                                                                    
1819                                                                                                          
1820     void enableChildrenCache(int fromPage, int toPage) {                                                 
1821         if (fromPage > toPage) {                                                                         
1822             final int temp = fromPage;                                                                   
1823             fromPage = toPage;                                                                           
1824             toPage = temp;                                                                               
1825         }                                                                                                
1826                                                                                                          
1827         final int screenCount = getChildCount();                                                         
1828                                                                                                          
1829         fromPage = Math.max(fromPage, 0);                                                                
1830         toPage = Math.min(toPage, screenCount - 1);                                                      
1831                                                                                                          
1832         for (int i = fromPage; i <= toPage; i++) {                                                       
1833             final CellLayout layout = (CellLayout) getChildAt(i);                                        
1834             layout.setChildrenDrawnWithCacheEnabled(true);                                               
1835             layout.setChildrenDrawingCacheEnabled(true);                                                 
1836         }                                                                                                
1837     }                                                                                                    
1838                                                                                                          
1839     void clearChildrenCache() {                                                                          
1840         final int screenCount = getChildCount();                                                         
1841         for (int i = 0; i < screenCount; i++) {                                                          
1842             final CellLayout layout = (CellLayout) getChildAt(i);                                        
1843             layout.setChildrenDrawnWithCacheEnabled(false);                                              
1844             // In software mode, we don't want the items to continue to be drawn into bitmaps            
1845             if (!isHardwareAccelerated()) {                                                              
1846                 layout.setChildrenDrawingCacheEnabled(false);                                            
1847             }                                                                                            
1848         }                                                                                                
1849     }                                                                                                    
1850                                                                                                          
1851     private void updateChildrenLayersEnabled(boolean force) {                                            
1852         boolean small = (mState == State.OVERVIEW) || mIsSwitchingState;                                 
1853         boolean enableChildrenLayers = ((force || small) || mAnimatingViewIntoPlace) || isPageMoving();  
1854         if (enableChildrenLayers != mChildrenLayersEnabled) {                                            
1855             mChildrenLayersEnabled = enableChildrenLayers;                                               
1856             if (mChildrenLayersEnabled) {                                                                
1857                 enableHwLayersOnVisiblePages();                                                          
1858             } else {                                                                                     
1859                 for (int i = 0; i < getPageCount(); i++) {                                               
1860                     final CellLayout cl = ((CellLayout) (getChildAt(i)));                                
1861                     cl.enableHardwareLayer(false);                                                       
1862                 }                                                                                        
1863             }                                                                                            
1864         }                                                                                                
1865     }                                                                                                    
1866                                                                                                          
1867     private void enableHwLayersOnVisiblePages() {                                                        
1868         if (mChildrenLayersEnabled) {                                                                    
1869             final int screenCount = getChildCount();                                                     
1870             getVisiblePages(mTempVisiblePagesRange);                                                     
1871             int leftScreen = mTempVisiblePagesRange[0];                                                  
1872             int rightScreen = mTempVisiblePagesRange[1];                                                 
1873             if (leftScreen == rightScreen) {                                                             
1874                 // make sure we're caching at least two pages always                                     
1875                 if (rightScreen < screenCount - 1) {                                                     
1876                     rightScreen++;                                                                       
1877                 } else if (leftScreen > 0) {                                                             
1878                     leftScreen--;                                                                        
1879                 }                                                                                        
1880             }                                                                                            
1881                                                                                                          
1882             final CellLayout customScreen = mWorkspaceScreens.get(CUSTOM_CONTENT_SCREEN_ID);             
1883             for (int i = 0; i < screenCount; i++) {                                                      
1884                 final CellLayout layout = (CellLayout) getPageAt(i);                                     
1885                                                                                                          
1886                 // enable layers between left and right screen inclusive, except for the                 
1887                 // customScreen, which may animate its content during transitions.                       
1888                 boolean enableLayer = layout != customScreen &&                                          
1889                         leftScreen <= i && i <= rightScreen && shouldDrawChild(layout);                  
1890                 layout.enableHardwareLayer(enableLayer);                                                 
1891             }                                                                                            
1892         }                                                                                                
1893     }                                                                                                    
1894                                                                                                          
1895     public void buildPageHardwareLayers() {                                                              
1896         // force layers to be enabled just for the call to buildLayer                                    
1897         updateChildrenLayersEnabled(true);                                                               
1898         if (getWindowToken() != null) {                                                                  
1899             final int childCount = getChildCount();                                                      
1900             for (int i = 0; i < childCount; i++) {                                                       
1901                 CellLayout cl = (CellLayout) getChildAt(i);                                              
1902                 cl.buildHardwareLayer();                                                                 
1903             }                                                                                            
1904         }                                                                                                
1905         updateChildrenLayersEnabled(false);                                                              
1906     }                                                                                                    
1907                                                                                                          
1908     protected void onWallpaperTap(MotionEvent ev) {                                                      
1909         final int[] position = mTempCell;                                                                
1910         getLocationOnScreen(position);                                                                   
1911                                                                                                          
1912         int pointerIndex = ev.getActionIndex();                                                          
1913         position[0] += (int) ev.getX(pointerIndex);                                                      
1914         position[1] += (int) ev.getY(pointerIndex);                                                      
1915                                                                                                          
1916         mWallpaperManager.sendWallpaperCommand(getWindowToken(),                                         
1917                 ev.getAction() == MotionEvent.ACTION_UP                                                  
1918                         ? WallpaperManager.COMMAND_TAP : WallpaperManager.COMMAND_SECONDARY_TAP,         
1919                 position[0], position[1], 0, null);                                                      
1920     }                                                                                                    
1921                                                                                                          
1922     /* This interpolator emulates the rate at which the perceived scale of an object changes             
1923     as its distance from a camera increases. When this interpolator is applied to a scale                
1924     animation on a view, it evokes the sense that the object is shrinking due to moving away             
1925     from the camera.                                                                                     
1926      */                                                                                                  
1927     static class ZInterpolator implements TimeInterpolator {                                             
1928         private float focalLength;                                                                       
1929                                                                                                          
1930         public ZInterpolator(float foc) {                                                                
1931             focalLength = foc;                                                                           
1932         }                                                                                                
1933                                                                                                          
1934         public float getInterpolation(float input) {                                                     
1935             return (1.0F - (focalLength / (focalLength + input))) / (1.0F - (focalLength / (focalLength +🔵
1936         }                                                                                                
1937     }                                                                                                    
1938                                                                                                          
1939     /* The exact reverse of ZInterpolator. */                                                            
1940     static class InverseZInterpolator implements TimeInterpolator {                                      
1941         private ZInterpolator zInterpolator;                                                             
1942                                                                                                          
1943         public InverseZInterpolator(float foc) {                                                         
1944             zInterpolator = new ZInterpolator(foc);                                                      
1945         }                                                                                                
1946                                                                                                          
1947         public float getInterpolation(float input) {                                                     
1948             return 1 - zInterpolator.getInterpolation(1 - input);                                        
1949         }                                                                                                
1950     }                                                                                                    
1951                                                                                                          
1952     /* ZInterpolator compounded with an ease-out. */                                                     
1953     static class ZoomOutInterpolator implements TimeInterpolator {                                       
1954         private final DecelerateInterpolator decelerate = new DecelerateInterpolator(0.75F);             
1955                                                                                                          
1956         private final ZInterpolator zInterpolator = new ZInterpolator(0.13F);                            
1957                                                                                                          
1958         public float getInterpolation(float input) {                                                     
1959             return decelerate.getInterpolation(zInterpolator.getInterpolation(input));                   
1960         }                                                                                                
1961     }                                                                                                    
1962                                                                                                          
1963     /* InvereZInterpolator compounded with an ease-out. */                                               
1964     static class ZoomInInterpolator implements TimeInterpolator {                                        
1965         private final InverseZInterpolator inverseZInterpolator = new InverseZInterpolator(0.35F);       
1966                                                                                                          
1967         private final DecelerateInterpolator decelerate = new DecelerateInterpolator(3.0F);              
1968                                                                                                          
1969         public float getInterpolation(float input) {                                                     
1970             return decelerate.getInterpolation(inverseZInterpolator.getInterpolation(input));            
1971         }                                                                                                
1972     }                                                                                                    
1973                                                                                                          
1974     private final ZoomInInterpolator mZoomInInterpolator = new ZoomInInterpolator();                     
1975                                                                                                          
1976     /*                                                                                                   
1977     *                                                                                                    
1978     * We call these methods (onDragStartedWithItemSpans/onDragStartedWithSize) whenever we               
1979     * start a drag in Launcher, regardless of whether the drag has ever entered the Workspace            
1980     *                                                                                                    
1981     * These methods mark the appropriate pages as accepting drops (which alters their visual             
1982     * appearance).                                                                                       
1983     *                                                                                                    
1984     */                                                                                                   
1985     private static Rect getDrawableBounds(Drawable d) {                                                  
1986         Rect bounds = new Rect();                                                                        
1987         d.copyBounds(bounds);                                                                            
1988         if ((bounds.width() == 0) || (bounds.height() == 0)) {                                           
1989             bounds.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());                             
1990         } else {                                                                                         
1991             bounds.offsetTo(0, 0);                                                                       
1992         }                                                                                                
1993         if (d instanceof PreloadIconDrawable) {                                                          
1994             int inset = -((PreloadIconDrawable) (d)).getOutset();                                        
1995             bounds.inset(inset, inset);                                                                  
1996         }                                                                                                
1997         return bounds;                                                                                   
1998     }                                                                                                    
1999                                                                                                          
2000     public void onExternalDragStartedWithItem(View v) {                                                  
2001         // Compose a drag bitmap with the view scaled to the icon size                                   
2002         LauncherAppState app = LauncherAppState.getInstance();                                           
2003         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                    
2004         int iconSize = grid.iconSizePx;                                                                  
2005         int bmpWidth = v.getMeasuredWidth();                                                             
2006         int bmpHeight = v.getMeasuredHeight();                                                           
2007         // If this is a text view, use its drawable instead                                              
2008         if (v instanceof TextView) {                                                                     
2009             TextView tv = ((TextView) (v));                                                              
2010             Drawable d = tv.getCompoundDrawables()[1];                                                   
2011             Rect bounds = getDrawableBounds(d);                                                          
2012             bmpWidth = bounds.width();                                                                   
2013             bmpHeight = bounds.height();                                                                 
2014         }                                                                                                
2015         // Compose the bitmap to create the icon from                                                    
2016         Bitmap b = Bitmap.createBitmap(bmpWidth, bmpHeight, Bitmap.Config.ARGB_8888);                    
2017         mCanvas.setBitmap(b);                                                                            
2018         drawDragView(v, mCanvas, 0);                                                                     
2019         mCanvas.setBitmap(null);                                                                         
2020         // The outline is used to visualize where the item will land if dropped                          
2021         mDragOutline = createDragOutline(b, DRAG_BITMAP_PADDING, iconSize, iconSize, true);              
2022     }                                                                                                    
2023                                                                                                          
2024     public void onDragStartedWithItem(PendingAddItemInfo info, Bitmap b, boolean clipAlpha) {            
2025         int[] size = estimateItemSize(info.spanX, info.spanY, info, false);                              
2026         // The outline is used to visualize where the item will land if dropped                          
2027         mDragOutline = createDragOutline(b, DRAG_BITMAP_PADDING, size[0], size[1], clipAlpha);           
2028     }                                                                                                    
2029                                                                                                          
2030     public void exitWidgetResizeMode() {                                                                 
2031         DragLayer dragLayer = mLauncher.getDragLayer();                                                  
2032         dragLayer.clearAllResizeFrames();                                                                
2033     }                                                                                                    
2034                                                                                                          
2035     private void initAnimationArrays() {                                                                 
2036         final int childCount = getChildCount();                                                          
2037         if (mLastChildCount == childCount) return;                                                       
2038                                                                                                          
2039         mOldBackgroundAlphas = new float[childCount];                                                    
2040         mOldAlphas = new float[childCount];                                                              
2041         mNewBackgroundAlphas = new float[childCount];                                                    
2042         mNewAlphas = new float[childCount];                                                              
2043     }                                                                                                    
2044                                                                                                          
2045     Animator getChangeStateAnimation(final State state, boolean animated, ArrayList<View> layerViews) {  
2046         return getChangeStateAnimation(state, animated, 0, -1, layerViews);                              
2047     }                                                                                                    
2048                                                                                                          
2049     @Override                                                                                            
2050     protected void getFreeScrollPageRange(int[] range) {                                                 
2051         getOverviewModePages(range);                                                                     
2052     }                                                                                                    
2053                                                                                                          
2054     private void getOverviewModePages(int[] range) {                                                     
2055         int start = numCustomPages();                                                                    
2056         int end = getChildCount() - 1;                                                                   
2057         range[0] = Math.max(0, Math.min(start, getChildCount() - 1));                                    
2058         range[1] = Math.max(0, end);                                                                     
2059     }                                                                                                    
2060                                                                                                          
2061     protected void onStartReordering() {                                                                 
2062         super.onStartReordering();                                                                       
2063         showOutlines();                                                                                  
2064         // Reordering handles its own animations, disable the automatic ones.                            
2065         disableLayoutTransitions();                                                                      
2066     }                                                                                                    
2067                                                                                                          
2068     protected void onEndReordering() {                                                                   
2069         super.onEndReordering();                                                                         
2070         if (mLauncher.isWorkspaceLoading()) {                                                            
2071             // Invalid and dangerous operation if workspace is loading                                   
2072             return;                                                                                      
2073         }                                                                                                
2074         hideOutlines();                                                                                  
2075         mScreenOrder.clear();                                                                            
2076         int count = getChildCount();                                                                     
2077         for (int i = 0; i < count; i++) {                                                                
2078             CellLayout cl = ((CellLayout) (getChildAt(i)));                                              
2079             mScreenOrder.add(getIdForScreen(cl));                                                        
2080         }                                                                                                
2081         mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder);                        
2082         // Re-enable auto layout transitions for page deletion.                                          
2083         enableLayoutTransitions();                                                                       
2084     }                                                                                                    
2085                                                                                                          
2086     public boolean isInOverviewMode() {                                                                  
2087         return mState == State.OVERVIEW;                                                                 
2088     }                                                                                                    
2089                                                                                                          
2090     public boolean enterOverviewMode() {                                                                 
2091         if (mTouchState != TOUCH_STATE_REST) {                                                           
2092             return false;                                                                                
2093         }                                                                                                
2094         enableOverviewMode(true, -1, true);                                                              
2095         return true;                                                                                     
2096     }                                                                                                    
2097                                                                                                          
2098     public void exitOverviewMode(boolean animated) {                                                     
2099         exitOverviewMode(-1, animated);                                                                  
2100     }                                                                                                    
2101                                                                                                          
2102     public void exitOverviewMode(int snapPage, boolean animated) {                                       
2103         enableOverviewMode(false, snapPage, animated);                                                   
2104     }                                                                                                    
2105                                                                                                          
2106     private void enableOverviewMode(boolean enable, int snapPage, boolean animated) {                    
2107         State finalState = Workspace.State.OVERVIEW;                                                     
2108         if (!enable) {                                                                                   
2109             finalState = Workspace.State.NORMAL;                                                         
2110         }                                                                                                
2111                                                                                                          
2112         Animator workspaceAnim = getChangeStateAnimation(finalState, animated, 0, snapPage);             
2113         if (workspaceAnim != null) {                                                                     
2114             onTransitionPrepare();                                                                       
2115             workspaceAnim.addListener(new AnimatorListenerAdapter() {                                    
2116                 @Override                                                                                
2117                 public void onAnimationEnd(Animator arg0) {                                              
2118                     onTransitionEnd();                                                                   
2119                 }                                                                                        
2120             });                                                                                          
2121             workspaceAnim.start();                                                                       
2122         }                                                                                                
2123     }                                                                                                    
2124                                                                                                          
2125     int getOverviewModeTranslationY() {                                                                  
2126         LauncherAppState app = LauncherAppState.getInstance();                                           
2127         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                    
2128         Rect overviewBar = grid.getOverviewModeButtonBarRect();                                          
2129                                                                                                          
2130         int availableHeight = getViewportHeight();                                                       
2131         int scaledHeight = (int) (mOverviewModeShrinkFactor * getNormalChildHeight());                   
2132         int offsetFromTopEdge = (availableHeight - scaledHeight) / 2;                                    
2133         int offsetToCenterInOverview = (availableHeight - mInsets.top - overviewBar.height()             
2134                 - scaledHeight) / 2;                                                                     
2135                                                                                                          
2136         return -offsetFromTopEdge + mInsets.top + offsetToCenterInOverview;                              
2137     }                                                                                                    
2138                                                                                                          
2139     boolean shouldVoiceButtonProxyBeVisible() {                                                          
2140         if (isOnOrMovingToCustomContent()) {                                                             
2141             return false;                                                                                
2142         }                                                                                                
2143         if (mState != State.NORMAL) {                                                                    
2144             return false;                                                                                
2145         }                                                                                                
2146         return true;                                                                                     
2147     }                                                                                                    
2148                                                                                                          
2149     public void updateInteractionForState() {                                                            
2150         if (mState != State.NORMAL) {                                                                    
2151             mLauncher.onInteractionBegin();                                                              
2152         } else {                                                                                         
2153             mLauncher.onInteractionEnd();                                                                
2154         }                                                                                                
2155     }                                                                                                    
2156                                                                                                          
2157     private void setState(State state) {                                                                 
2158         mState = state;                                                                                  
2159         updateInteractionForState();                                                                     
2160         updateAccessibilityFlags();                                                                      
2161     }                                                                                                    
2162                                                                                                          
2163     State getState() {                                                                                   
2164         return mState;                                                                                   
2165     }                                                                                                    
2166                                                                                                          
2167     private void updateAccessibilityFlags() {                                                            
2168         int accessible = mState == State.NORMAL ?                                                        
2169                 ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES :                                             
2170                 ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS;                              
2171         setImportantForAccessibility(accessible);                                                        
2172     }                                                                                                    
2173                                                                                                          
2174     private static final int HIDE_WORKSPACE_DURATION = 100;                                              
2175                                                                                                          
2176     Animator getChangeStateAnimation(final State state, boolean animated, int delay, int snapPage) {     
2177         return getChangeStateAnimation(state, animated, delay, snapPage, null);                          
2178     }                                                                                                    
2179                                                                                                          
2180     Animator getChangeStateAnimation(final State state, boolean animated, int delay, int snapPage, ArrayL🔵
2181         if (mState == state) {                                                                           
2182             return null;                                                                                 
2183         }                                                                                                
2184         // Initialize animation arrays for the first time if necessary                                   
2185         initAnimationArrays();                                                                           
2186         AnimatorSet anim = (animated) ? LauncherAnimUtils.createAnimatorSet() : null;                    
2187         final State oldState = mState;                                                                   
2188         final boolean oldStateIsNormal = oldState == State.NORMAL;                                       
2189         final boolean oldStateIsSpringLoaded = oldState == State.SPRING_LOADED;                          
2190         final boolean oldStateIsNormalHidden = oldState == State.NORMAL_HIDDEN;                          
2191         final boolean oldStateIsOverviewHidden = oldState == State.OVERVIEW_HIDDEN;                      
2192         final boolean oldStateIsOverview = oldState == State.OVERVIEW;                                   
2193         setState(state);                                                                                 
2194         final boolean stateIsNormal = state == State.NORMAL;                                             
2195         final boolean stateIsSpringLoaded = state == State.SPRING_LOADED;                                
2196         final boolean stateIsNormalHidden = state == State.NORMAL_HIDDEN;                                
2197         final boolean stateIsOverviewHidden = state == State.OVERVIEW_HIDDEN;                            
2198         final boolean stateIsOverview = state == State.OVERVIEW;                                         
2199         float finalBackgroundAlpha = (stateIsSpringLoaded || stateIsOverview) ? 1.0F : 0.0F;             
2200         float finalHotseatAndPageIndicatorAlpha = (stateIsNormal || stateIsSpringLoaded) ? 1.0F : 0.0F;  
2201         float finalOverviewPanelAlpha = (stateIsOverview) ? 1.0F : 0.0F;                                 
2202         float finalSearchBarAlpha = (!stateIsNormal) ? 0.0F : 1.0F;                                      
2203         float finalWorkspaceTranslationY = (stateIsOverview || stateIsOverviewHidden) ? getOverviewModeTr🔵
2204         boolean workspaceToAllApps = oldStateIsNormal && stateIsNormalHidden;                            
2205         boolean overviewToAllApps = oldStateIsOverview && stateIsOverviewHidden;                         
2206         boolean allAppsToWorkspace = stateIsNormalHidden && stateIsNormal;                               
2207         boolean workspaceToOverview = oldStateIsNormal && stateIsOverview;                               
2208         boolean overviewToWorkspace = oldStateIsOverview && stateIsNormal;                               
2209         mNewScale = 1.0F;                                                                                
2210         if (oldStateIsOverview) {                                                                        
2211             disableFreeScroll();                                                                         
2212         } else if (stateIsOverview) {                                                                    
2213             enableFreeScroll();                                                                          
2214         }                                                                                                
2215         if (state != State.NORMAL) {                                                                     
2216             if (stateIsSpringLoaded) {                                                                   
2217                 mNewScale = mSpringLoadedShrinkFactor;                                                   
2218             } else if (stateIsOverview || stateIsOverviewHidden) {                                       
2219                 mNewScale = mOverviewModeShrinkFactor;                                                   
2220             }                                                                                            
2221         }                                                                                                
2222         final int duration;                                                                              
2223         if (workspaceToAllApps || overviewToAllApps) {                                                   
2224             //getResources().getInteger(R.integer.config_workspaceUnshrinkTime);                         
2225             duration = HIDE_WORKSPACE_DURATION;                                                          
2226         } else if (workspaceToOverview || overviewToWorkspace) {                                         
2227             duration = getResources().getInteger(R.integer.config_overviewTransitionTime);               
2228         } else {                                                                                         
2229             duration = getResources().getInteger(R.integer.config_appsCustomizeWorkspaceShrinkTime);     
2230         }                                                                                                
2231         if (snapPage == (-1)) {                                                                          
2232             snapPage = getPageNearestToCenterOfScreen();                                                 
2233         }                                                                                                
2234         snapToPage(snapPage, duration, mZoomInInterpolator);                                             
2235         for (int i = 0; i < getChildCount(); i++) {                                                      
2236             final CellLayout cl = ((CellLayout) (getChildAt(i)));                                        
2237             boolean isCurrentPage = i == snapPage;                                                       
2238             float initialAlpha = cl.getShortcutsAndWidgets().getAlpha();                                 
2239             float finalAlpha;                                                                            
2240             if (stateIsNormalHidden || stateIsOverviewHidden) {                                          
2241                 finalAlpha = 0.0F;                                                                       
2242             } else if (stateIsNormal && mWorkspaceFadeInAdjacentScreens) {                               
2243                 finalAlpha = ((i == snapPage) || (i < numCustomPages())) ? 1.0F : 0.0F;                  
2244             } else {                                                                                     
2245                 finalAlpha = 1.0F;                                                                       
2246             }                                                                                            
2247             // If we are animating to/from the small state, then hide the side pages and fade the        
2248             // current page in                                                                           
2249             if (!mIsSwitchingState) {                                                                    
2250                 if (workspaceToAllApps || allAppsToWorkspace) {                                          
2251                     if (allAppsToWorkspace && isCurrentPage) {                                           
2252                         initialAlpha = 0.0F;                                                             
2253                     } else if (!isCurrentPage) {                                                         
2254                         initialAlpha = finalAlpha = 0.0F;                                                
2255                     }                                                                                    
2256                     cl.setShortcutAndWidgetAlpha(initialAlpha);                                          
2257                 }                                                                                        
2258             }                                                                                            
2259             mOldAlphas[i] = initialAlpha;                                                                
2260             mNewAlphas[i] = finalAlpha;                                                                  
2261             if (animated) {                                                                              
2262                 mOldBackgroundAlphas[i] = cl.getBackgroundAlpha();                                       
2263                 mNewBackgroundAlphas[i] = finalBackgroundAlpha;                                          
2264             } else {                                                                                     
2265                 cl.setBackgroundAlpha(finalBackgroundAlpha);                                             
2266                 cl.setShortcutAndWidgetAlpha(finalAlpha);                                                
2267             }                                                                                            
2268         }                                                                                                
2269         final View searchBar = mLauncher.getQsbBar();                                                    
2270         final View overviewPanel = mLauncher.getOverviewPanel();                                         
2271         final View hotseat = mLauncher.getHotseat();                                                     
2272         final View pageIndicator = getPageIndicator();                                                   
2273         if (animated) {                                                                                  
2274             LauncherViewPropertyAnimator scale = new LauncherViewPropertyAnimator(this);                 
2275             scale.scaleX(mNewScale).scaleY(mNewScale).translationY(finalWorkspaceTranslationY).setDuratio🔵
2276             anim.play(scale);                                                                            
2277             for (int index = 0; index < getChildCount(); index++) {                                      
2278                 final int i = index;                                                                     
2279                 final CellLayout cl = ((CellLayout) (getChildAt(i)));                                    
2280                 float currentAlpha = cl.getShortcutsAndWidgets().getAlpha();                             
2281                 if ((mOldAlphas[i] == 0) && (mNewAlphas[i] == 0)) {                                      
2282                     cl.setBackgroundAlpha(mNewBackgroundAlphas[i]);                                      
2283                     cl.setShortcutAndWidgetAlpha(mNewAlphas[i]);                                         
2284                 } else {                                                                                 
2285                     if (layerViews != null) {                                                            
2286                         layerViews.add(cl);                                                              
2287                     }                                                                                    
2288                     if ((mOldAlphas[i] != mNewAlphas[i]) || (currentAlpha != mNewAlphas[i])) {           
2289                         LauncherViewPropertyAnimator alphaAnim = new LauncherViewPropertyAnimator(cl.getS🔵
2290                         alphaAnim.alpha(mNewAlphas[i]).setDuration(duration).setInterpolator(mZoomInInter🔵
2291                         anim.play(alphaAnim);                                                            
2292                     }                                                                                    
2293                     if ((mOldBackgroundAlphas[i] != 0) || (mNewBackgroundAlphas[i] != 0)) {              
2294                         ValueAnimator bgAnim = LauncherAnimUtils.ofFloat(cl, 0.0F, 1.0F);                
2295                         bgAnim.setInterpolator(mZoomInInterpolator);                                     
2296                         bgAnim.setDuration(duration);                                                    
2297                         bgAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {                  
2298                             public void onAnimationUpdate(float a, float b) {                            
2299                                 cl.setBackgroundAlpha((a * mOldBackgroundAlphas[i]) + (b * mNewBackground🔵
2300                             }                                                                            
2301                         });                                                                              
2302                         anim.play(bgAnim);                                                               
2303                     }                                                                                    
2304                 }                                                                                        
2305             }                                                                                            
2306             Animator pageIndicatorAlpha = null;                                                          
2307             if (pageIndicator != null) {                                                                 
2308                 pageIndicatorAlpha = new LauncherViewPropertyAnimator(pageIndicator).alpha(finalHotseatAn🔵
2309                 pageIndicatorAlpha.addListener(new AlphaUpdateListener(pageIndicator));                  
2310             } else {                                                                                     
2311                 // create a dummy animation so we don't need to do null checks later                     
2312                 pageIndicatorAlpha = ValueAnimator.ofFloat(0, 0);                                        
2313             }                                                                                            
2314             Animator hotseatAlpha = new LauncherViewPropertyAnimator(hotseat).alpha(finalHotseatAndPageIn🔵
2315             hotseatAlpha.addListener(new AlphaUpdateListener(hotseat));                                  
2316             Animator searchBarAlpha = new LauncherViewPropertyAnimator(searchBar).alpha(finalSearchBarAlp🔵
2317             searchBarAlpha.addListener(new AlphaUpdateListener(searchBar));                              
2318             Animator overviewPanelAlpha = new LauncherViewPropertyAnimator(overviewPanel).alpha(finalOver🔵
2319             overviewPanelAlpha.addListener(new AlphaUpdateListener(overviewPanel));                      
2320             // For animation optimations, we may need to provide the Launcher transition                 
2321             // with a set of views on which to force build layers in certain scenarios.                  
2322             hotseat.setLayerType(View.LAYER_TYPE_HARDWARE, null);                                        
2323             searchBar.setLayerType(View.LAYER_TYPE_HARDWARE, null);                                      
2324             overviewPanel.setLayerType(View.LAYER_TYPE_HARDWARE, null);                                  
2325             if (layerViews != null) {                                                                    
2326                 layerViews.add(hotseat);                                                                 
2327                 layerViews.add(searchBar);                                                               
2328                 layerViews.add(overviewPanel);                                                           
2329             }                                                                                            
2330             if (workspaceToOverview) {                                                                   
2331                 pageIndicatorAlpha.setInterpolator(new DecelerateInterpolator(2));                       
2332                 hotseatAlpha.setInterpolator(new DecelerateInterpolator(2));                             
2333                 overviewPanelAlpha.setInterpolator(null);                                                
2334             } else if (overviewToWorkspace) {                                                            
2335                 pageIndicatorAlpha.setInterpolator(null);                                                
2336                 hotseatAlpha.setInterpolator(null);                                                      
2337                 overviewPanelAlpha.setInterpolator(new DecelerateInterpolator(2));                       
2338             }                                                                                            
2339             overviewPanelAlpha.setDuration(duration);                                                    
2340             pageIndicatorAlpha.setDuration(duration);                                                    
2341             hotseatAlpha.setDuration(duration);                                                          
2342             searchBarAlpha.setDuration(duration);                                                        
2343             anim.play(overviewPanelAlpha);                                                               
2344             anim.play(hotseatAlpha);                                                                     
2345             anim.play(searchBarAlpha);                                                                   
2346             anim.play(pageIndicatorAlpha);                                                               
2347             anim.setStartDelay(delay);                                                                   
2348         } else {                                                                                         
2349             overviewPanel.setAlpha(finalOverviewPanelAlpha);                                             
2350             AlphaUpdateListener.updateVisibility(overviewPanel);                                         
2351             hotseat.setAlpha(finalHotseatAndPageIndicatorAlpha);                                         
2352             AlphaUpdateListener.updateVisibility(hotseat);                                               
2353             if (pageIndicator != null) {                                                                 
2354                 pageIndicator.setAlpha(finalHotseatAndPageIndicatorAlpha);                               
2355                 AlphaUpdateListener.updateVisibility(pageIndicator);                                     
2356             }                                                                                            
2357             searchBar.setAlpha(finalSearchBarAlpha);                                                     
2358             AlphaUpdateListener.updateVisibility(searchBar);                                             
2359             updateCustomContentVisibility();                                                             
2360             setScaleX(mNewScale);                                                                        
2361             setScaleY(mNewScale);                                                                        
2362             setTranslationY(finalWorkspaceTranslationY);                                                 
2363         }                                                                                                
2364         mLauncher.updateVoiceButtonProxyVisible(false);                                                  
2365         if (stateIsNormal) {                                                                             
2366             animateBackgroundGradient(0.0F, animated);                                                   
2367         } else {                                                                                         
2368             animateBackgroundGradient(getResources().getInteger(R.integer.config_workspaceScrimAlpha) / 1🔵
2369         }                                                                                                
2370         return anim;                                                                                     
2371     }                                                                                                    
2372                                                                                                          
2373     static class AlphaUpdateListener implements AnimatorUpdateListener , AnimatorListener {              
2374         View view;                                                                                       
2375                                                                                                          
2376         public AlphaUpdateListener(View v) {                                                             
2377             view = v;                                                                                    
2378         }                                                                                                
2379                                                                                                          
2380         @Override                                                                                        
2381         public void onAnimationUpdate(ValueAnimator arg0) {                                              
2382             updateVisibility(view);                                                                      
2383         }                                                                                                
2384                                                                                                          
2385         public static void updateVisibility(View view) {                                                 
2386             // We want to avoid the extra layout pass by setting the views to GONE unless                
2387             // accessibility is on, in which case not setting them to GONE causes a glitch.              
2388             int invisibleState = (sAccessibilityEnabled) ? GONE : INVISIBLE;                             
2389             if ((view.getAlpha() < ALPHA_CUTOFF_THRESHOLD) && (view.getVisibility() != invisibleState)) {
2390                 view.setVisibility(invisibleState);                                                      
2391             } else if ((view.getAlpha() > ALPHA_CUTOFF_THRESHOLD) && (view.getVisibility() != VISIBLE)) {
2392                 view.setVisibility(VISIBLE);                                                             
2393             }                                                                                            
2394         }                                                                                                
2395                                                                                                          
2396         @Override                                                                                        
2397         public void onAnimationCancel(Animator arg0) {                                                   
2398         }                                                                                                
2399                                                                                                          
2400         @Override                                                                                        
2401         public void onAnimationEnd(Animator arg0) {                                                      
2402             updateVisibility(view);                                                                      
2403         }                                                                                                
2404                                                                                                          
2405         @Override                                                                                        
2406         public void onAnimationRepeat(Animator arg0) {                                                   
2407         }                                                                                                
2408                                                                                                          
2409         @Override                                                                                        
2410         public void onAnimationStart(Animator arg0) {                                                    
2411             // We want the views to be visible for animation, so fade-in/out is visible                  
2412             view.setVisibility(VISIBLE);                                                                 
2413         }                                                                                                
2414     }                                                                                                    
2415                                                                                                          
2416     @Override                                                                                            
2417     public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) {         
2418         onTransitionPrepare();                                                                           
2419     }                                                                                                    
2420                                                                                                          
2421     @Override                                                                                            
2422     public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) {           
2423     }                                                                                                    
2424                                                                                                          
2425     @Override                                                                                            
2426     public void onLauncherTransitionStep(Launcher l, float t) {                                          
2427         mTransitionProgress = t;                                                                         
2428     }                                                                                                    
2429                                                                                                          
2430     @Override                                                                                            
2431     public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {             
2432         onTransitionEnd();                                                                               
2433     }                                                                                                    
2434                                                                                                          
2435     private void onTransitionPrepare() {                                                                 
2436         mIsSwitchingState = true;                                                                        
2437                                                                                                          
2438         // Invalidate here to ensure that the pages are rendered during the state change transition.     
2439         invalidate();                                                                                    
2440                                                                                                          
2441         updateChildrenLayersEnabled(false);                                                              
2442         hideCustomContentIfNecessary();                                                                  
2443     }                                                                                                    
2444                                                                                                          
2445     void updateCustomContentVisibility() {                                                               
2446         int visibility = mState == Workspace.State.NORMAL ? VISIBLE : INVISIBLE;                         
2447         if (hasCustomContent()) {                                                                        
2448             mWorkspaceScreens.get(CUSTOM_CONTENT_SCREEN_ID).setVisibility(visibility);                   
2449         }                                                                                                
2450     }                                                                                                    
2451                                                                                                          
2452     void showCustomContentIfNecessary() {                                                                
2453         boolean show  = mState == Workspace.State.NORMAL;                                                
2454         if (show && hasCustomContent()) {                                                                
2455             mWorkspaceScreens.get(CUSTOM_CONTENT_SCREEN_ID).setVisibility(VISIBLE);                      
2456         }                                                                                                
2457     }                                                                                                    
2458                                                                                                          
2459     void hideCustomContentIfNecessary() {                                                                
2460         boolean hide  = mState != Workspace.State.NORMAL;                                                
2461         if (hide && hasCustomContent()) {                                                                
2462             disableLayoutTransitions();                                                                  
2463             mWorkspaceScreens.get(CUSTOM_CONTENT_SCREEN_ID).setVisibility(INVISIBLE);                    
2464             enableLayoutTransitions();                                                                   
2465         }                                                                                                
2466     }                                                                                                    
2467                                                                                                          
2468     private void onTransitionEnd() {                                                                     
2469         mIsSwitchingState = false;                                                                       
2470         updateChildrenLayersEnabled(false);                                                              
2471         showCustomContentIfNecessary();                                                                  
2472     }                                                                                                    
2473                                                                                                          
2474     @Override                                                                                            
2475     public View getContent() {                                                                           
2476         return this;                                                                                     
2477     }                                                                                                    
2478                                                                                                          
2479     /**                                                                                                  
2480      * Draw the View v into the given Canvas.                                                            
2481      *                                                                                                   
2482      * @param v the view to draw                                                                         
2483      * @param destCanvas the canvas to draw on                                                           
2484      * @param padding the horizontal and vertical padding to use when drawing                            
2485      */                                                                                                  
2486     private static void drawDragView(View v, Canvas destCanvas, int padding) {                           
2487         final Rect clipRect = sTempRect;                                                                 
2488         v.getDrawingRect(clipRect);                                                                      
2489         boolean textVisible = false;                                                                     
2490         destCanvas.save();                                                                               
2491         if (v instanceof TextView) {                                                                     
2492             Drawable d = ((TextView) (v)).getCompoundDrawables()[1];                                     
2493             Rect bounds = getDrawableBounds(d);                                                          
2494             clipRect.set(0, 0, bounds.width() + padding, bounds.height() + padding);                     
2495             destCanvas.translate((padding / 2) - bounds.left, (padding / 2) - bounds.top);               
2496             d.draw(destCanvas);                                                                          
2497         } else {                                                                                         
2498             if (v instanceof FolderIcon) {                                                               
2499                 // For FolderIcons the text can bleed into the icon area, and so we need to              
2500                 // hide the text completely (which can't be achieved by clipping).                       
2501                 if (((FolderIcon) (v)).getTextVisible()) {                                               
2502                     ((FolderIcon) (v)).setTextVisible(false);                                            
2503                     textVisible = true;                                                                  
2504                 }                                                                                        
2505             }                                                                                            
2506             destCanvas.translate((-v.getScrollX()) + (padding / 2), (-v.getScrollY()) + (padding / 2));  
2507             destCanvas.clipRect(clipRect, Op.REPLACE);                                                   
2508             v.draw(destCanvas);                                                                          
2509             // Restore text visibility of FolderIcon if necessary                                        
2510             if (textVisible) {                                                                           
2511                 ((FolderIcon) (v)).setTextVisible(true);                                                 
2512             }                                                                                            
2513         }                                                                                                
2514         destCanvas.restore();                                                                            
2515     }                                                                                                    
2516                                                                                                          
2517     /**                                                                                                  
2518      * Returns a new bitmap to show when the given View is being dragged around.                         
2519      * Responsibility for the bitmap is transferred to the caller.                                       
2520      *                                                                                                   
2521      * @param expectedPadding                                                                            
2522      * 		padding to add to the drag view. If a different padding was used                                
2523      * 		its value will be changed                                                                       
2524      */                                                                                                  
2525     public Bitmap createDragBitmap(View v, AtomicInteger expectedPadding) {                              
2526         Bitmap b;                                                                                        
2527         int padding = expectedPadding.get();                                                             
2528         if (v instanceof TextView) {                                                                     
2529             Drawable d = ((TextView) (v)).getCompoundDrawables()[1];                                     
2530             Rect bounds = getDrawableBounds(d);                                                          
2531             b = Bitmap.createBitmap(bounds.width() + padding, bounds.height() + padding, Bitmap.Config.AR🔵
2532             expectedPadding.set((padding - bounds.left) - bounds.top);                                   
2533         } else {                                                                                         
2534             b = Bitmap.createBitmap(v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8🔵
2535         }                                                                                                
2536         mCanvas.setBitmap(b);                                                                            
2537         drawDragView(v, mCanvas, padding);                                                               
2538         mCanvas.setBitmap(null);                                                                         
2539         return b;                                                                                        
2540     }                                                                                                    
2541                                                                                                          
2542     /**                                                                                                  
2543      * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.       
2544      * Responsibility for the bitmap is transferred to the caller.                                       
2545      */                                                                                                  
2546     private Bitmap createDragOutline(View v, int padding) {                                              
2547         final int outlineColor = getResources().getColor(R.color.outline_color);                         
2548         final Bitmap b = Bitmap.createBitmap(v.getWidth() + padding, v.getHeight() + padding, Bitmap.Conf🔵
2549         mCanvas.setBitmap(b);                                                                            
2550         drawDragView(v, mCanvas, padding);                                                               
2551         mOutlineHelper.applyExpensiveOutlineWithBlur(b, mCanvas, outlineColor, outlineColor);            
2552         mCanvas.setBitmap(null);                                                                         
2553         return b;                                                                                        
2554     }                                                                                                    
2555                                                                                                          
2556     /**                                                                                                  
2557      * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.       
2558      * Responsibility for the bitmap is transferred to the caller.                                       
2559      */                                                                                                  
2560     private Bitmap createDragOutline(Bitmap orig, int padding, int w, int h, boolean clipAlpha) {        
2561         final int outlineColor = getResources().getColor(R.color.outline_color);                         
2562         final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);                             
2563         mCanvas.setBitmap(b);                                                                            
2564         Rect src = new Rect(0, 0, orig.getWidth(), orig.getHeight());                                    
2565         float scaleFactor = Math.min((w - padding) / ((float) (orig.getWidth())), (h - padding) / ((float🔵
2566         int scaledWidth = ((int) (scaleFactor * orig.getWidth()));                                       
2567         int scaledHeight = ((int) (scaleFactor * orig.getHeight()));                                     
2568         Rect dst = new Rect(0, 0, scaledWidth, scaledHeight);                                            
2569         // center the image                                                                              
2570         dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2);                                       
2571         mCanvas.drawBitmap(orig, src, dst, null);                                                        
2572         mOutlineHelper.applyExpensiveOutlineWithBlur(b, mCanvas, outlineColor, outlineColor, clipAlpha); 
2573         mCanvas.setBitmap(null);                                                                         
2574         return b;                                                                                        
2575     }                                                                                                    
2576                                                                                                          
2577     void startDrag(CellLayout.CellInfo cellInfo) {                                                       
2578         View child = cellInfo.cell;                                                                      
2579         // Make sure the drag was started by a long press as opposed to a long click.                    
2580         if (!child.isInTouchMode()) {                                                                    
2581             return;                                                                                      
2582         }                                                                                                
2583         mDragInfo = cellInfo;                                                                            
2584         child.setVisibility(INVISIBLE);                                                                  
2585         CellLayout layout = ((CellLayout) (child.getParent().getParent()));                              
2586         layout.prepareChildForDrag(child);                                                               
2587         beginDragShared(child, this);                                                                    
2588     }                                                                                                    
2589                                                                                                          
2590     public void beginDragShared(View child, DragSource source) {                                         
2591         child.clearFocus();                                                                              
2592         child.setPressed(false);                                                                         
2593         // The outline is used to visualize where the item will land if dropped                          
2594         mDragOutline = createDragOutline(child, DRAG_BITMAP_PADDING);                                    
2595         mLauncher.onDragStarted(child);                                                                  
2596         // The drag bitmap follows the touch point around on the screen                                  
2597         AtomicInteger padding = new AtomicInteger(DRAG_BITMAP_PADDING);                                  
2598         final Bitmap b = createDragBitmap(child, padding);                                               
2599         final int bmpWidth = b.getWidth();                                                               
2600         final int bmpHeight = b.getHeight();                                                             
2601         float scale = mLauncher.getDragLayer().getLocationInDragLayer(child, mTempXY);                   
2602         int dragLayerX = Math.round(mTempXY[0] - ((bmpWidth - (scale * child.getWidth())) / 2));         
2603         int dragLayerY = Math.round((mTempXY[1] - ((bmpHeight - (scale * bmpHeight)) / 2)) - (padding.get🔵
2604         LauncherAppState app = LauncherAppState.getInstance();                                           
2605         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                    
2606         Point dragVisualizeOffset = null;                                                                
2607         Rect dragRect = null;                                                                            
2608         if (child instanceof BubbleTextView) {                                                           
2609             int iconSize = grid.iconSizePx;                                                              
2610             int top = child.getPaddingTop();                                                             
2611             int left = (bmpWidth - iconSize) / 2;                                                        
2612             int right = left + iconSize;                                                                 
2613             int bottom = top + iconSize;                                                                 
2614             dragLayerY += top;                                                                           
2615             // Note: The drag region is used to calculate drag layer offsets, but the                    
2616             // dragVisualizeOffset in addition to the dragRect (the size) to position the outline.       
2617             dragVisualizeOffset = new Point((-padding.get()) / 2, padding.get() / 2);                    
2618             dragRect = new Rect(left, top, right, bottom);                                               
2619         } else if (child instanceof FolderIcon) {                                                        
2620             int previewSize = grid.folderIconSizePx;                                                     
2621             dragRect = new Rect(0, child.getPaddingTop(), child.getWidth(), previewSize);                
2622         }                                                                                                
2623         // Clear the pressed state if necessary                                                          
2624         if (child instanceof BubbleTextView) {                                                           
2625             BubbleTextView icon = ((BubbleTextView) (child));                                            
2626             icon.clearPressedBackground();                                                               
2627         }                                                                                                
2628         if ((child.getTag() == null) || (!(child.getTag() instanceof ItemInfo))) {                       
2629             String msg = ((("Drag started with a view that has no tag set. This " + ("will cause a crash 🔵
2630             throw new IllegalStateException(msg);                                                        
2631         }                                                                                                
2632         DragView dv = mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(), DragCo🔵
2633         dv.setIntrinsicIconScaleFactor(source.getIntrinsicIconScaleFactor());                            
2634         if (child.getParent() instanceof ShortcutAndWidgetContainer) {                                   
2635             mDragSourceInternal = ((ShortcutAndWidgetContainer) (child.getParent()));                    
2636         }                                                                                                
2637         b.recycle();                                                                                     
2638     }                                                                                                    
2639                                                                                                          
2640     public void beginExternalDragShared(View child, DragSource source) {                                 
2641         LauncherAppState app = LauncherAppState.getInstance();                                           
2642         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                    
2643         int iconSize = grid.iconSizePx;                                                                  
2644         // Notify launcher of drag start                                                                 
2645         mLauncher.onDragStarted(child);                                                                  
2646         // Compose a new drag bitmap that is of the icon size                                            
2647         AtomicInteger padding = new AtomicInteger(DRAG_BITMAP_PADDING);                                  
2648         final Bitmap tmpB = createDragBitmap(child, padding);                                            
2649         Bitmap b = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);                     
2650         Paint p = new Paint();                                                                           
2651         p.setFilterBitmap(true);                                                                         
2652         mCanvas.setBitmap(b);                                                                            
2653         mCanvas.drawBitmap(tmpB, new Rect(0, 0, tmpB.getWidth(), tmpB.getHeight()), new Rect(0, 0, iconSi🔵
2654         mCanvas.setBitmap(null);                                                                         
2655         // Find the child's location on the screen                                                       
2656         int bmpWidth = tmpB.getWidth();                                                                  
2657         float iconScale = ((float) (bmpWidth)) / iconSize;                                               
2658         float scale = mLauncher.getDragLayer().getLocationInDragLayer(child, mTempXY) * iconScale;       
2659         int dragLayerX = Math.round(mTempXY[0] - ((bmpWidth - (scale * child.getWidth())) / 2));         
2660         int dragLayerY = Math.round(mTempXY[1]);                                                         
2661         // Note: The drag region is used to calculate drag layer offsets, but the                        
2662         // dragVisualizeOffset in addition to the dragRect (the size) to position the outline.           
2663         Point dragVisualizeOffset = new Point((-padding.get()) / 2, padding.get() / 2);                  
2664         Rect dragRect = new Rect(0, 0, iconSize, iconSize);                                              
2665         if ((child.getTag() == null) || (!(child.getTag() instanceof ItemInfo))) {                       
2666             String msg = ((("Drag started with a view that has no tag set. This " + ("will cause a crash 🔵
2667             throw new IllegalStateException(msg);                                                        
2668         }                                                                                                
2669         // Start the drag                                                                                
2670         DragView dv = mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(), DragCo🔵
2671         dv.setIntrinsicIconScaleFactor(source.getIntrinsicIconScaleFactor());                            
2672         // Recycle temporary bitmaps                                                                     
2673         tmpB.recycle();                                                                                  
2674     }                                                                                                    
2675                                                                                                          
2676     void addApplicationShortcut(ShortcutInfo info, CellLayout target, long container, long screenId,     
2677             int cellX, int cellY, boolean insertAtFirst, int intersectX, int intersectY) {               
2678         View view = mLauncher.createShortcut(R.layout.application, target, (ShortcutInfo) info);         
2679                                                                                                          
2680         final int[] cellXY = new int[2];                                                                 
2681         target.findCellForSpanThatIntersects(cellXY, 1, 1, intersectX, intersectY);                      
2682         addInScreen(view, container, screenId, cellXY[0], cellXY[1], 1, 1, insertAtFirst);               
2683                                                                                                          
2684         LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screenId, cellXY[0],           
2685                 cellXY[1]);                                                                              
2686     }                                                                                                    
2687                                                                                                          
2688     public boolean transitionStateShouldAllowDrop() {                                                    
2689         return ((!isSwitchingState()) || (mTransitionProgress > 0.5F)) && ((mState == State.NORMAL) || (m🔵
2690     }                                                                                                    
2691                                                                                                          
2692     /**                                                                                                  
2693      * {@inheritDoc}                                                                                     
2694      */                                                                                                  
2695     public boolean acceptDrop(DragObject d) {                                                            
2696         // If it's an external drop (e.g. from All Apps), check if it should be accepted                 
2697         CellLayout dropTargetLayout = mDropToLayout;                                                     
2698         if (d.dragSource != this) {                                                                      
2699             // Don't accept the drop if we're not over a screen at time of drop                          
2700             if (dropTargetLayout == null) {                                                              
2701                 return false;                                                                            
2702             }                                                                                            
2703             if (!transitionStateShouldAllowDrop()) {                                                     
2704                 return false;                                                                            
2705             }                                                                                            
2706             mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, d.dragView, m🔵
2707             // We want the point to be mapped to the dragTarget.                                         
2708             if (mLauncher.isHotseatLayout(dropTargetLayout)) {                                           
2709                 mapPointFromSelfToHotseatLayout(mLauncher.getHotseat(), mDragViewVisualCenter);          
2710             } else {                                                                                     
2711                 mapPointFromSelfToChild(dropTargetLayout, mDragViewVisualCenter, null);                  
2712             }                                                                                            
2713             int spanX = 1;                                                                               
2714             int spanY = 1;                                                                               
2715             if (mDragInfo != null) {                                                                     
2716                 final CellLayout.CellInfo dragCellInfo = mDragInfo;                                      
2717                 spanX = dragCellInfo.spanX;                                                              
2718                 spanY = dragCellInfo.spanY;                                                              
2719             } else {                                                                                     
2720                 final ItemInfo dragInfo = ((ItemInfo) (d.dragInfo));                                     
2721                 spanX = dragInfo.spanX;                                                                  
2722                 spanY = dragInfo.spanY;                                                                  
2723             }                                                                                            
2724             int minSpanX = spanX;                                                                        
2725             int minSpanY = spanY;                                                                        
2726             if (d.dragInfo instanceof PendingAddWidgetInfo) {                                            
2727                 minSpanX = ((PendingAddWidgetInfo) (d.dragInfo)).minSpanX;                               
2728                 minSpanY = ((PendingAddWidgetInfo) (d.dragInfo)).minSpanY;                               
2729             }                                                                                            
2730             mTargetCell = findNearestArea(((int) (mDragViewVisualCenter[0])), ((int) (mDragViewVisualCent🔵
2731             float distance = dropTargetLayout.getDistanceFromCell(mDragViewVisualCenter[0], mDragViewVisu🔵
2732             if (mCreateUserFolderOnDrop && willCreateUserFolder(((ItemInfo) (d.dragInfo)), dropTargetLayo🔵
2733                 return true;                                                                             
2734             }                                                                                            
2735             if (mAddToExistingFolderOnDrop && willAddToExistingUserFolder(((ItemInfo) (d.dragInfo)), drop🔵
2736                 return true;                                                                             
2737             }                                                                                            
2738             int[] resultSpan = new int[2];                                                               
2739             mTargetCell = dropTargetLayout.performReorder(((int) (mDragViewVisualCenter[0])), ((int) (mDr🔵
2740             boolean foundCell = (mTargetCell[0] >= 0) && (mTargetCell[1] >= 0);                          
2741             // Don't accept the drop if there's no room for the item                                     
2742             if (!foundCell) {                                                                            
2743                 // Don't show the message if we are dropping on the AllApps button and the hotseat       
2744                 // is full                                                                               
2745                 boolean isHotseat = mLauncher.isHotseatLayout(dropTargetLayout);                         
2746                 if ((mTargetCell != null) && isHotseat) {                                                
2747                     Hotseat hotseat = mLauncher.getHotseat();                                            
2748                     if (hotseat.isAllAppsButtonRank(hotseat.getOrderInHotseat(mTargetCell[0], mTargetCell🔵
2749                         return false;                                                                    
2750                     }                                                                                    
2751                 }                                                                                        
2752                 mLauncher.showOutOfSpaceMessage(isHotseat);                                              
2753                 return false;                                                                            
2754             }                                                                                            
2755         }                                                                                                
2756         long screenId = getIdForScreen(dropTargetLayout);                                                
2757         if (screenId == EXTRA_EMPTY_SCREEN_ID) {                                                         
2758             commitExtraEmptyScreen();                                                                    
2759         }                                                                                                
2760         return true;                                                                                     
2761     }                                                                                                    
2762                                                                                                          
2763     boolean willCreateUserFolder(ItemInfo info, CellLayout target, int[] targetCell, float               
2764             distance, boolean considerTimeout) {                                                         
2765         if (distance > mMaxDistanceForFolderCreation) return false;                                      
2766         View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);                             
2767                                                                                                          
2768         if (dropOverView != null) {                                                                      
2769             CellLayout.LayoutParams lp = (CellLayout.LayoutParams) dropOverView.getLayoutParams();       
2770             if (lp.useTmpCoords && (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.tmpCellY)) {            
2771                 return false;                                                                            
2772             }                                                                                            
2773         }                                                                                                
2774                                                                                                          
2775         boolean hasntMoved = false;                                                                      
2776         if (mDragInfo != null) {                                                                         
2777             hasntMoved = dropOverView == mDragInfo.cell;                                                 
2778         }                                                                                                
2779                                                                                                          
2780         if (dropOverView == null || hasntMoved || (considerTimeout && !mCreateUserFolderOnDrop)) {       
2781             return false;                                                                                
2782         }                                                                                                
2783                                                                                                          
2784         boolean aboveShortcut = (dropOverView.getTag() instanceof ShortcutInfo);                         
2785         boolean willBecomeShortcut =                                                                     
2786                 (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||                    
2787                 info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT);                         
2788                                                                                                          
2789         return (aboveShortcut && willBecomeShortcut);                                                    
2790     }                                                                                                    
2791                                                                                                          
2792     boolean willAddToExistingUserFolder(Object dragInfo, CellLayout target, int[] targetCell,            
2793             float distance) {                                                                            
2794         if (distance > mMaxDistanceForFolderCreation) return false;                                      
2795         View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);                             
2796                                                                                                          
2797         if (dropOverView != null) {                                                                      
2798             CellLayout.LayoutParams lp = (CellLayout.LayoutParams) dropOverView.getLayoutParams();       
2799             if (lp.useTmpCoords && (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.tmpCellY)) {            
2800                 return false;                                                                            
2801             }                                                                                            
2802         }                                                                                                
2803                                                                                                          
2804         if (dropOverView instanceof FolderIcon) {                                                        
2805             FolderIcon fi = (FolderIcon) dropOverView;                                                   
2806             if (fi.acceptDrop(dragInfo)) {                                                               
2807                 return true;                                                                             
2808             }                                                                                            
2809         }                                                                                                
2810         return false;                                                                                    
2811     }                                                                                                    
2812                                                                                                          
2813     boolean createUserFolderIfNecessary(View newView, long container, CellLayout target,                 
2814             int[] targetCell, float distance, boolean external, DragView dragView,                       
2815             Runnable postAnimationRunnable) {                                                            
2816         if (distance > mMaxDistanceForFolderCreation) return false;                                      
2817         View v = target.getChildAt(targetCell[0], targetCell[1]);                                        
2818                                                                                                          
2819         boolean hasntMoved = false;                                                                      
2820         if (mDragInfo != null) {                                                                         
2821             CellLayout cellParent = getParentCellLayoutForView(mDragInfo.cell);                          
2822             hasntMoved = (mDragInfo.cellX == targetCell[0] &&                                            
2823                     mDragInfo.cellY == targetCell[1]) && (cellParent == target);                         
2824         }                                                                                                
2825                                                                                                          
2826         if (v == null || hasntMoved || !mCreateUserFolderOnDrop) return false;                           
2827         mCreateUserFolderOnDrop = false;                                                                 
2828         final long screenId = (targetCell == null) ? mDragInfo.screenId : getIdForScreen(target);        
2829                                                                                                          
2830         boolean aboveShortcut = (v.getTag() instanceof ShortcutInfo);                                    
2831         boolean willBecomeShortcut = (newView.getTag() instanceof ShortcutInfo);                         
2832                                                                                                          
2833         if (aboveShortcut && willBecomeShortcut) {                                                       
2834             ShortcutInfo sourceInfo = (ShortcutInfo) newView.getTag();                                   
2835             ShortcutInfo destInfo = (ShortcutInfo) v.getTag();                                           
2836             // if the drag started here, we need to remove it from the workspace                         
2837             if (!external) {                                                                             
2838                 getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell);                   
2839             }                                                                                            
2840                                                                                                          
2841             Rect folderLocation = new Rect();                                                            
2842             float scale = mLauncher.getDragLayer().getDescendantRectRelativeToSelf(v, folderLocation);   
2843             target.removeView(v);                                                                        
2844                                                                                                          
2845             FolderIcon fi =                                                                              
2846                 mLauncher.addFolder(target, container, screenId, targetCell[0], targetCell[1]);          
2847             destInfo.cellX = -1;                                                                         
2848             destInfo.cellY = -1;                                                                         
2849             sourceInfo.cellX = -1;                                                                       
2850             sourceInfo.cellY = -1;                                                                       
2851                                                                                                          
2852             // If the dragView is null, we can't animate                                                 
2853             boolean animate = dragView != null;                                                          
2854             if (animate) {                                                                               
2855                 fi.performCreateAnimation(destInfo, v, sourceInfo, dragView, folderLocation, scale,      
2856                         postAnimationRunnable);                                                          
2857             } else {                                                                                     
2858                 fi.addItem(destInfo);                                                                    
2859                 fi.addItem(sourceInfo);                                                                  
2860             }                                                                                            
2861             return true;                                                                                 
2862         }                                                                                                
2863         return false;                                                                                    
2864     }                                                                                                    
2865                                                                                                          
2866     boolean addToExistingFolderIfNecessary(View newView, CellLayout target, int[] targetCell,            
2867             float distance, DragObject d, boolean external) {                                            
2868         if (distance > mMaxDistanceForFolderCreation) return false;                                      
2869                                                                                                          
2870         View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);                             
2871         if (!mAddToExistingFolderOnDrop) return false;                                                   
2872         mAddToExistingFolderOnDrop = false;                                                              
2873                                                                                                          
2874         if (dropOverView instanceof FolderIcon) {                                                        
2875             FolderIcon fi = (FolderIcon) dropOverView;                                                   
2876             if (fi.acceptDrop(d.dragInfo)) {                                                             
2877                 fi.onDrop(d);                                                                            
2878                                                                                                          
2879                 // if the drag started here, we need to remove it from the workspace                     
2880                 if (!external) {                                                                         
2881                     getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell);               
2882                 }                                                                                        
2883                 return true;                                                                             
2884             }                                                                                            
2885         }                                                                                                
2886         return false;                                                                                    
2887     }                                                                                                    
2888                                                                                                          
2889     public void onDrop(final DragObject d) {                                                             
2890         mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, d.dragView, mDrag🔵
2891         CellLayout dropTargetLayout = mDropToLayout;                                                     
2892         // We want the point to be mapped to the dragTarget.                                             
2893         if (dropTargetLayout != null) {                                                                  
2894             if (mLauncher.isHotseatLayout(dropTargetLayout)) {                                           
2895                 mapPointFromSelfToHotseatLayout(mLauncher.getHotseat(), mDragViewVisualCenter);          
2896             } else {                                                                                     
2897                 mapPointFromSelfToChild(dropTargetLayout, mDragViewVisualCenter, null);                  
2898             }                                                                                            
2899         }                                                                                                
2900         int snapScreen = -1;                                                                             
2901         boolean resizeOnDrop = false;                                                                    
2902         if (d.dragSource != this) {                                                                      
2903             final int[] touchXY = new int[]{ ((int) (mDragViewVisualCenter[0])), ((int) (mDragViewVisualC🔵
2904             onDropExternal(touchXY, d.dragInfo, dropTargetLayout, false, d);                             
2905         } else if (mDragInfo != null) {                                                                  
2906             final View cell = mDragInfo.cell;                                                            
2907             Runnable resizeRunnable = null;                                                              
2908             if ((dropTargetLayout != null) && (!d.cancelled)) {                                          
2909                 // Move internally                                                                       
2910                 boolean hasMovedLayouts = getParentCellLayoutForView(cell) != dropTargetLayout;          
2911                 boolean hasMovedIntoHotseat = mLauncher.isHotseatLayout(dropTargetLayout);               
2912                 long container = (hasMovedIntoHotseat) ? Favorites.CONTAINER_HOTSEAT : Favorites.CONTAINE🔵
2913                 long screenId = (mTargetCell[0] < 0) ? mDragInfo.screenId : getIdForScreen(dropTargetLayo🔵
2914                 int spanX = (mDragInfo != null) ? mDragInfo.spanX : 1;                                   
2915                 int spanY = (mDragInfo != null) ? mDragInfo.spanY : 1;                                   
2916                 // First we find the cell nearest to point at which the item is                          
2917                 // dropped, without any consideration to whether there is an item there.                 
2918                 mTargetCell = findNearestArea(((int) (mDragViewVisualCenter[0])), ((int) (mDragViewVisual🔵
2919                 float distance = dropTargetLayout.getDistanceFromCell(mDragViewVisualCenter[0], mDragView🔵
2920                 // If the item being dropped is a shortcut and the nearest drop                          
2921                 // cell also contains a shortcut, then create a folder with the two shortcuts.           
2922                 if ((!mInScrollArea) && createUserFolderIfNecessary(cell, container, dropTargetLayout, mT🔵
2923                     return;                                                                              
2924                 }                                                                                        
2925                 if (addToExistingFolderIfNecessary(cell, dropTargetLayout, mTargetCell, distance, d, fals🔵
2926                     return;                                                                              
2927                 }                                                                                        
2928                 // Aside from the special case where we're dropping a shortcut onto a shortcut,          
2929                 // we need to find the nearest cell location that is vacant                              
2930                 ItemInfo item = ((ItemInfo) (d.dragInfo));                                               
2931                 int minSpanX = item.spanX;                                                               
2932                 int minSpanY = item.spanY;                                                               
2933                 if ((item.minSpanX > 0) && (item.minSpanY > 0)) {                                        
2934                     minSpanX = item.minSpanX;                                                            
2935                     minSpanY = item.minSpanY;                                                            
2936                 }                                                                                        
2937                 int[] resultSpan = new int[2];                                                           
2938                 mTargetCell = dropTargetLayout.performReorder(((int) (mDragViewVisualCenter[0])), ((int) 🔵
2939                 boolean foundCell = (mTargetCell[0] >= 0) && (mTargetCell[1] >= 0);                      
2940                 // if the widget resizes on drop                                                         
2941                 if ((foundCell && (cell instanceof AppWidgetHostView)) && ((resultSpan[0] != item.spanX) 🔵
2942                     resizeOnDrop = true;                                                                 
2943                     item.spanX = resultSpan[0];                                                          
2944                     item.spanY = resultSpan[1];                                                          
2945                     AppWidgetHostView awhv = ((AppWidgetHostView) (cell));                               
2946                     AppWidgetResizeFrame.updateWidgetSizeRanges(awhv, mLauncher, resultSpan[0], resultSpa🔵
2947                 }                                                                                        
2948                 if ((getScreenIdForPageIndex(mCurrentPage) != screenId) && (!hasMovedIntoHotseat)) {     
2949                     snapScreen = getPageIndexForScreenId(screenId);                                      
2950                     snapToPage(snapScreen);                                                              
2951                 }                                                                                        
2952                 if (foundCell) {                                                                         
2953                     final ItemInfo info = ((ItemInfo) (cell.getTag()));                                  
2954                     if (hasMovedLayouts) {                                                               
2955                         // Reparent the view                                                             
2956                         CellLayout parentCell = getParentCellLayoutForView(cell);                        
2957                         if (parentCell != null) {                                                        
2958                             parentCell.removeView(cell);                                                 
2959                         } else if (LauncherAppState.isDogfoodBuild()) {                                  
2960                             throw new NullPointerException("mDragInfo.cell has null parent");            
2961                         }                                                                                
2962                         addInScreen(cell, container, screenId, mTargetCell[0], mTargetCell[1], info.spanX🔵
2963                     }                                                                                    
2964                     // update the item's position after drop                                             
2965                     CellLayout.LayoutParams lp = ((CellLayout.LayoutParams) (cell.getLayoutParams()));   
2966                     lp.cellX = lp.tmpCellX = mTargetCell[0];                                             
2967                     lp.cellY = lp.tmpCellY = mTargetCell[1];                                             
2968                     lp.cellHSpan = item.spanX;                                                           
2969                     lp.cellVSpan = item.spanY;                                                           
2970                     lp.isLockedToGrid = true;                                                            
2971                     if ((container != Favorites.CONTAINER_HOTSEAT) && (cell instanceof LauncherAppWidgetH🔵
2972                         final CellLayout cellLayout = dropTargetLayout;                                  
2973                         // We post this call so that the widget has a chance to be placed                
2974                         // in its final location                                                         
2975                         final LauncherAppWidgetHostView hostView = ((LauncherAppWidgetHostView) (cell)); 
2976                         AppWidgetProviderInfo pinfo = hostView.getAppWidgetInfo();                       
2977                         if ((pinfo != null) && (pinfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE)) {
2978                             final Runnable addResizeFrame = new Runnable() {                             
2979                                 public void run() {                                                      
2980                                     DragLayer dragLayer = mLauncher.getDragLayer();                      
2981                                     dragLayer.addResizeFrame(info, hostView, cellLayout);                
2982                                 }                                                                        
2983                             };                                                                           
2984                             resizeRunnable = new Runnable() {                                            
2985                                 public void run() {                                                      
2986                                     if (!isPageMoving()) {                                               
2987                                         addResizeFrame.run();                                            
2988                                     } else {                                                             
2989                                         mDelayedResizeRunnable = addResizeFrame;                         
2990                                     }                                                                    
2991                                 }                                                                        
2992                             };                                                                           
2993                         }                                                                                
2994                     }                                                                                    
2995                     LauncherModel.modifyItemInDatabase(mLauncher, info, container, screenId, lp.cellX, lp🔵
2996                 } else {                                                                                 
2997                     // If we can't find a drop location, we return the item to its original position     
2998                     CellLayout.LayoutParams lp = ((CellLayout.LayoutParams) (cell.getLayoutParams()));   
2999                     mTargetCell[0] = lp.cellX;                                                           
3000                     mTargetCell[1] = lp.cellY;                                                           
3001                     CellLayout layout = ((CellLayout) (cell.getParent().getParent()));                   
3002                     layout.markCellsAsOccupiedForView(cell);                                             
3003                 }                                                                                        
3004             }                                                                                            
3005             final CellLayout parent = ((CellLayout) (cell.getParent().getParent()));                     
3006             final Runnable finalResizeRunnable = resizeRunnable;                                         
3007             // Prepare it to be animated into its new position                                           
3008             // This must be called after the view has been re-parented                                   
3009             final Runnable onCompleteRunnable = new Runnable() {                                         
3010                 @Override                                                                                
3011                 public void run() {                                                                      
3012                     mAnimatingViewIntoPlace = false;                                                     
3013                     updateChildrenLayersEnabled(false);                                                  
3014                     if (finalResizeRunnable != null) {                                                   
3015                         finalResizeRunnable.run();                                                       
3016                     }                                                                                    
3017                 }                                                                                        
3018             };                                                                                           
3019             mAnimatingViewIntoPlace = true;                                                              
3020             if (d.dragView.hasDrawn()) {                                                                 
3021                 final ItemInfo info = ((ItemInfo) (cell.getTag()));                                      
3022                 if (info.itemType == Favorites.ITEM_TYPE_APPWIDGET) {                                    
3023                     int animationType = (resizeOnDrop) ? ANIMATE_INTO_POSITION_AND_RESIZE : ANIMATE_INTO_🔵
3024                     animateWidgetDrop(info, parent, d.dragView, onCompleteRunnable, animationType, cell, 🔵
3025                 } else {                                                                                 
3026                     int duration = (snapScreen < 0) ? -1 : ADJACENT_SCREEN_DROP_DURATION;                
3027                     mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, cell, duration, onComple🔵
3028                 }                                                                                        
3029             } else {                                                                                     
3030                 d.deferDragViewCleanupPostAnimation = false;                                             
3031                 cell.setVisibility(VISIBLE);                                                             
3032             }                                                                                            
3033             parent.onDropChild(cell);                                                                    
3034         }                                                                                                
3035     }                                                                                                    
3036                                                                                                          
3037     public void setFinalScrollForPageChange(int pageIndex) {                                             
3038         CellLayout cl = (CellLayout) getChildAt(pageIndex);                                              
3039         if (cl != null) {                                                                                
3040             mSavedScrollX = getScrollX();                                                                
3041             mSavedTranslationX = cl.getTranslationX();                                                   
3042             mSavedRotationY = cl.getRotationY();                                                         
3043             final int newX = getScrollForPage(pageIndex);                                                
3044             setScrollX(newX);                                                                            
3045             cl.setTranslationX(0f);                                                                      
3046             cl.setRotationY(0f);                                                                         
3047         }                                                                                                
3048     }                                                                                                    
3049                                                                                                          
3050     public void resetFinalScrollForPageChange(int pageIndex) {                                           
3051         if (pageIndex >= 0) {                                                                            
3052             CellLayout cl = (CellLayout) getChildAt(pageIndex);                                          
3053             setScrollX(mSavedScrollX);                                                                   
3054             cl.setTranslationX(mSavedTranslationX);                                                      
3055             cl.setRotationY(mSavedRotationY);                                                            
3056         }                                                                                                
3057     }                                                                                                    
3058                                                                                                          
3059     public void getViewLocationRelativeToSelf(View v, int[] location) {                                  
3060         getLocationInWindow(location);                                                                   
3061         int x = location[0];                                                                             
3062         int y = location[1];                                                                             
3063                                                                                                          
3064         v.getLocationInWindow(location);                                                                 
3065         int vX = location[0];                                                                            
3066         int vY = location[1];                                                                            
3067                                                                                                          
3068         location[0] = vX - x;                                                                            
3069         location[1] = vY - y;                                                                            
3070     }                                                                                                    
3071                                                                                                          
3072     public void onDragEnter(DragObject d) {                                                              
3073         mDragEnforcer.onDragEnter();                                                                     
3074         mCreateUserFolderOnDrop = false;                                                                 
3075         mAddToExistingFolderOnDrop = false;                                                              
3076         mDropToLayout = null;                                                                            
3077         CellLayout layout = getCurrentDropLayout();                                                      
3078         setCurrentDropLayout(layout);                                                                    
3079         setCurrentDragOverlappingLayout(layout);                                                         
3080         if (!workspaceInModalState()) {                                                                  
3081             mLauncher.getDragLayer().showPageHints();                                                    
3082         }                                                                                                
3083     }                                                                                                    
3084                                                                                                          
3085     /** Return a rect that has the cellWidth/cellHeight (left, top), and                                 
3086      * widthGap/heightGap (right, bottom) */                                                             
3087     static Rect getCellLayoutMetrics(Launcher launcher, int orientation) {                               
3088         LauncherAppState app = LauncherAppState.getInstance();                                           
3089         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                    
3090         Display display = launcher.getWindowManager().getDefaultDisplay();                               
3091         Point smallestSize = new Point();                                                                
3092         Point largestSize = new Point();                                                                 
3093         display.getCurrentSizeRange(smallestSize, largestSize);                                          
3094         int countX = ((int) (grid.numColumns));                                                          
3095         int countY = ((int) (grid.numRows));                                                             
3096         if (orientation == CellLayout.LANDSCAPE) {                                                       
3097             if (mLandscapeCellLayoutMetrics == null) {                                                   
3098                 Rect padding = grid.getWorkspacePadding(CellLayout.LANDSCAPE);                           
3099                 int width = (largestSize.x - padding.left) - padding.right;                              
3100                 int height = (smallestSize.y - padding.top) - padding.bottom;                            
3101                 mLandscapeCellLayoutMetrics = new Rect();                                                
3102                 mLandscapeCellLayoutMetrics.set(grid.calculateCellWidth(width, countX), grid.calculateCel🔵
3103             }                                                                                            
3104             return mLandscapeCellLayoutMetrics;                                                          
3105         } else if (orientation == CellLayout.PORTRAIT) {                                                 
3106             if (mPortraitCellLayoutMetrics == null) {                                                    
3107                 Rect padding = grid.getWorkspacePadding(CellLayout.PORTRAIT);                            
3108                 int width = (smallestSize.x - padding.left) - padding.right;                             
3109                 int height = (largestSize.y - padding.top) - padding.bottom;                             
3110                 mPortraitCellLayoutMetrics = new Rect();                                                 
3111                 mPortraitCellLayoutMetrics.set(grid.calculateCellWidth(width, countX), grid.calculateCell🔵
3112             }                                                                                            
3113             return mPortraitCellLayoutMetrics;                                                           
3114         }                                                                                                
3115         return null;                                                                                     
3116     }                                                                                                    
3117                                                                                                          
3118     public void onDragExit(DragObject d) {                                                               
3119         mDragEnforcer.onDragExit();                                                                      
3120         // Here we store the final page that will be dropped to, if the workspace in fact                
3121         // receives the drop                                                                             
3122         if (mInScrollArea) {                                                                             
3123             if (isPageMoving()) {                                                                        
3124                 // If the user drops while the page is scrolling, we should use that page as the         
3125                 // destination instead of the page that is being hovered over.                           
3126                 mDropToLayout = ((CellLayout) (getPageAt(getNextPage())));                               
3127             } else {                                                                                     
3128                 mDropToLayout = mDragOverlappingLayout;                                                  
3129             }                                                                                            
3130         } else {                                                                                         
3131             mDropToLayout = mDragTargetLayout;                                                           
3132         }                                                                                                
3133         if (mDragMode == DRAG_MODE_CREATE_FOLDER) {                                                      
3134             mCreateUserFolderOnDrop = true;                                                              
3135         } else if (mDragMode == DRAG_MODE_ADD_TO_FOLDER) {                                               
3136             mAddToExistingFolderOnDrop = true;                                                           
3137         }                                                                                                
3138         // Reset the scroll area and previous drag target                                                
3139         onResetScrollArea();                                                                             
3140         setCurrentDropLayout(null);                                                                      
3141         setCurrentDragOverlappingLayout(null);                                                           
3142         mSpringLoadedDragController.cancel();                                                            
3143         if (!mIsPageMoving) {                                                                            
3144             hideOutlines();                                                                              
3145         }                                                                                                
3146         mLauncher.getDragLayer().hidePageHints();                                                        
3147     }                                                                                                    
3148                                                                                                          
3149     void setCurrentDropLayout(CellLayout layout) {                                                       
3150         if (mDragTargetLayout != null) {                                                                 
3151             mDragTargetLayout.revertTempState();                                                         
3152             mDragTargetLayout.onDragExit();                                                              
3153         }                                                                                                
3154         mDragTargetLayout = layout;                                                                      
3155         if (mDragTargetLayout != null) {                                                                 
3156             mDragTargetLayout.onDragEnter();                                                             
3157         }                                                                                                
3158         cleanupReorder(true);                                                                            
3159         cleanupFolderCreation();                                                                         
3160         setCurrentDropOverCell(-1, -1);                                                                  
3161     }                                                                                                    
3162                                                                                                          
3163     void setCurrentDragOverlappingLayout(CellLayout layout) {                                            
3164         if (mDragOverlappingLayout != null) {                                                            
3165             mDragOverlappingLayout.setIsDragOverlapping(false);                                          
3166         }                                                                                                
3167         mDragOverlappingLayout = layout;                                                                 
3168         if (mDragOverlappingLayout != null) {                                                            
3169             mDragOverlappingLayout.setIsDragOverlapping(true);                                           
3170         }                                                                                                
3171         invalidate();                                                                                    
3172     }                                                                                                    
3173                                                                                                          
3174     void setCurrentDropOverCell(int x, int y) {                                                          
3175         if (x != mDragOverX || y != mDragOverY) {                                                        
3176             mDragOverX = x;                                                                              
3177             mDragOverY = y;                                                                              
3178             setDragMode(DRAG_MODE_NONE);                                                                 
3179         }                                                                                                
3180     }                                                                                                    
3181                                                                                                          
3182     void setDragMode(int dragMode) {                                                                     
3183         if (dragMode != mDragMode) {                                                                     
3184             if (dragMode == DRAG_MODE_NONE) {                                                            
3185                 cleanupAddToFolder();                                                                    
3186                 // We don't want to cancel the re-order alarm every time the target cell changes         
3187                 // as this feels to slow / unresponsive.                                                 
3188                 cleanupReorder(false);                                                                   
3189                 cleanupFolderCreation();                                                                 
3190             } else if (dragMode == DRAG_MODE_ADD_TO_FOLDER) {                                            
3191                 cleanupReorder(true);                                                                    
3192                 cleanupFolderCreation();                                                                 
3193             } else if (dragMode == DRAG_MODE_CREATE_FOLDER) {                                            
3194                 cleanupAddToFolder();                                                                    
3195                 cleanupReorder(true);                                                                    
3196             } else if (dragMode == DRAG_MODE_REORDER) {                                                  
3197                 cleanupAddToFolder();                                                                    
3198                 cleanupFolderCreation();                                                                 
3199             }                                                                                            
3200             mDragMode = dragMode;                                                                        
3201         }                                                                                                
3202     }                                                                                                    
3203                                                                                                          
3204     private void cleanupFolderCreation() {                                                               
3205         if (mDragFolderRingAnimator != null) {                                                           
3206             mDragFolderRingAnimator.animateToNaturalState();                                             
3207             mDragFolderRingAnimator = null;                                                              
3208         }                                                                                                
3209         mFolderCreationAlarm.setOnAlarmListener(null);                                                   
3210         mFolderCreationAlarm.cancelAlarm();                                                              
3211     }                                                                                                    
3212                                                                                                          
3213     private void cleanupAddToFolder() {                                                                  
3214         if (mDragOverFolderIcon != null) {                                                               
3215             mDragOverFolderIcon.onDragExit(null);                                                        
3216             mDragOverFolderIcon = null;                                                                  
3217         }                                                                                                
3218     }                                                                                                    
3219                                                                                                          
3220     private void cleanupReorder(boolean cancelAlarm) {                                                   
3221         // Any pending reorders are canceled                                                             
3222         if (cancelAlarm) {                                                                               
3223             mReorderAlarm.cancelAlarm();                                                                 
3224         }                                                                                                
3225         mLastReorderX = -1;                                                                              
3226         mLastReorderY = -1;                                                                              
3227     }                                                                                                    
3228                                                                                                          
3229 /*                                                                                                       
3230  *                                                                                                       
3231  * Convert the 2D coordinate xy from the parent View's coordinate space to this CellLayout's             
3232  * coordinate space. The argument xy is modified with the return result.                                 
3233  *                                                                                                       
3234  * if cachedInverseMatrix is not null, this method will just use that matrix instead of                  
3235  * computing it itself; we use this to avoid redundant matrix inversions in                              
3236  * findMatchingPageForDragOver                                                                           
3237  *                                                                                                       
3238  */                                                                                                      
3239 void mapPointFromSelfToChild(View v, float[] xy, Matrix cachedInverseMatrix) {                           
3240     xy[0] = xy[0] - v.getLeft();                                                                         
3241     xy[1] = xy[1] - v.getTop();                                                                          
3242 }                                                                                                        
3243                                                                                                          
3244 boolean isPointInSelfOverHotseat(int x, int y, Rect r) {                                                 
3245     if (r == null) {                                                                                     
3246         r = new Rect();                                                                                  
3247     }                                                                                                    
3248     mTempPt[0] = x;                                                                                      
3249     mTempPt[1] = y;                                                                                      
3250     mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempPt, true);                      
3251                                                                                                          
3252     LauncherAppState app = LauncherAppState.getInstance();                                               
3253     DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                        
3254     r = grid.getHotseatRect();                                                                           
3255     if (r.contains(mTempPt[0], mTempPt[1])) {                                                            
3256         return true;                                                                                     
3257     }                                                                                                    
3258     return false;                                                                                        
3259 }                                                                                                        
3260                                                                                                          
3261 void mapPointFromSelfToHotseatLayout(Hotseat hotseat, float[] xy) {                                      
3262     mTempPt[0] = (int) xy[0];                                                                            
3263     mTempPt[1] = (int) xy[1];                                                                            
3264     mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempPt, true);                      
3265     mLauncher.getDragLayer().mapCoordInSelfToDescendent(hotseat.getLayout(), mTempPt);                   
3266                                                                                                          
3267     xy[0] = mTempPt[0];                                                                                  
3268     xy[1] = mTempPt[1];                                                                                  
3269 }                                                                                                        
3270                                                                                                          
3271 /*                                                                                                       
3272  *                                                                                                       
3273  * Convert the 2D coordinate xy from this CellLayout's coordinate space to                               
3274  * the parent View's coordinate space. The argument xy is modified with the return result.               
3275  *                                                                                                       
3276  */                                                                                                      
3277 void mapPointFromChildToSelf(View v, float[] xy) {                                                       
3278     xy[0] += v.getLeft();                                                                                
3279     xy[1] += v.getTop();                                                                                 
3280 }                                                                                                        
3281                                                                                                          
3282 static private float squaredDistance(float[] point1, float[] point2) {                                   
3283      float distanceX = point1[0] - point2[0];                                                            
3284      float distanceY = point2[1] - point2[1];                                                            
3285      return distanceX * distanceX + distanceY * distanceY;                                               
3286 }                                                                                                        
3287                                                                                                          
3288     /*                                                                                                   
3289      *                                                                                                   
3290      * This method returns the CellLayout that is currently being dragged to. In order to drag           
3291      * to a CellLayout, either the touch point must be directly over the CellLayout, or as a second      
3292      * strategy, we see if the dragView is overlapping any CellLayout and choose the closest one         
3293      *                                                                                                   
3294      * Return null if no CellLayout is currently being dragged over                                      
3295      *                                                                                                   
3296      */                                                                                                  
3297     private CellLayout findMatchingPageForDragOver(                                                      
3298             DragView dragView, float originX, float originY, boolean exact) {                            
3299         // We loop through all the screens (ie CellLayouts) and see which ones overlap                   
3300         // with the item being dragged and then choose the one that's closest to the touch point         
3301         final int screenCount = getChildCount();                                                         
3302         CellLayout bestMatchingScreen = null;                                                            
3303         float smallestDistSoFar = Float.MAX_VALUE;                                                       
3304                                                                                                          
3305         for (int i = 0; i < screenCount; i++) {                                                          
3306             // The custom content screen is not a valid drag over option                                 
3307             if (mScreenOrder.get(i) == CUSTOM_CONTENT_SCREEN_ID) {                                       
3308                 continue;                                                                                
3309             }                                                                                            
3310                                                                                                          
3311             CellLayout cl = (CellLayout) getChildAt(i);                                                  
3312                                                                                                          
3313             final float[] touchXy = {originX, originY};                                                  
3314             // Transform the touch coordinates to the CellLayout's local coordinates                     
3315             // If the touch point is within the bounds of the cell layout, we can return immediately     
3316             cl.getMatrix().invert(mTempInverseMatrix);                                                   
3317             mapPointFromSelfToChild(cl, touchXy, mTempInverseMatrix);                                    
3318                                                                                                          
3319             if (touchXy[0] >= 0 && touchXy[0] <= cl.getWidth() &&                                        
3320                     touchXy[1] >= 0 && touchXy[1] <= cl.getHeight()) {                                   
3321                 return cl;                                                                               
3322             }                                                                                            
3323                                                                                                          
3324             if (!exact) {                                                                                
3325                 // Get the center of the cell layout in screen coordinates                               
3326                 final float[] cellLayoutCenter = mTempCellLayoutCenterCoordinates;                       
3327                 cellLayoutCenter[0] = cl.getWidth()/2;                                                   
3328                 cellLayoutCenter[1] = cl.getHeight()/2;                                                  
3329                 mapPointFromChildToSelf(cl, cellLayoutCenter);                                           
3330                                                                                                          
3331                 touchXy[0] = originX;                                                                    
3332                 touchXy[1] = originY;                                                                    
3333                                                                                                          
3334                 // Calculate the distance between the center of the CellLayout                           
3335                 // and the touch point                                                                   
3336                 float dist = squaredDistance(touchXy, cellLayoutCenter);                                 
3337                                                                                                          
3338                 if (dist < smallestDistSoFar) {                                                          
3339                     smallestDistSoFar = dist;                                                            
3340                     bestMatchingScreen = cl;                                                             
3341                 }                                                                                        
3342             }                                                                                            
3343         }                                                                                                
3344         return bestMatchingScreen;                                                                       
3345     }                                                                                                    
3346                                                                                                          
3347     // This is used to compute the visual center of the dragView. This point is then                     
3348     // used to visualize drop locations and determine where to drop an item. The idea is that            
3349     // the visual center represents the user's interpretation of where the item is, and hence            
3350     // is the appropriate point to use when determining drop location.                                   
3351     private float[] getDragViewVisualCenter(int x, int y, int xOffset, int yOffset,                      
3352             DragView dragView, float[] recycle) {                                                        
3353         float res[];                                                                                     
3354         if (recycle == null) {                                                                           
3355             res = new float[2];                                                                          
3356         } else {                                                                                         
3357             res = recycle;                                                                               
3358         }                                                                                                
3359                                                                                                          
3360         // First off, the drag view has been shifted in a way that is not represented in the             
3361         // x and y values or the x/yOffsets. Here we account for that shift.                             
3362         x += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetX);                              
3363         y += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY);                              
3364                                                                                                          
3365         // These represent the visual top and left of drag view if a dragRect was provided.              
3366         // If a dragRect was not provided, then they correspond to the actual view left and              
3367         // top, as the dragRect is in that case taken to be the entire dragView.                         
3368         // R.dimen.dragViewOffsetY.                                                                      
3369         int left = x - xOffset;                                                                          
3370         int top = y - yOffset;                                                                           
3371                                                                                                          
3372         // In order to find the visual center, we shift by half the dragRect                             
3373         res[0] = left + dragView.getDragRegion().width() / 2;                                            
3374         res[1] = top + dragView.getDragRegion().height() / 2;                                            
3375                                                                                                          
3376         return res;                                                                                      
3377     }                                                                                                    
3378                                                                                                          
3379     private boolean isDragWidget(DragObject d) {                                                         
3380         return (d.dragInfo instanceof LauncherAppWidgetInfo ||                                           
3381                 d.dragInfo instanceof PendingAddWidgetInfo);                                             
3382     }                                                                                                    
3383                                                                                                          
3384     private boolean isExternalDragWidget(DragObject d) {                                                 
3385         return d.dragSource != this && isDragWidget(d);                                                  
3386     }                                                                                                    
3387                                                                                                          
3388     public void onDragOver(DragObject d) {                                                               
3389         // Skip drag over events while we are dragging over side pages                                   
3390         if (mInScrollArea || (!transitionStateShouldAllowDrop())) {                                      
3391             return;                                                                                      
3392         }                                                                                                
3393         Rect r = new Rect();                                                                             
3394         CellLayout layout = null;                                                                        
3395         ItemInfo item = ((ItemInfo) (d.dragInfo));                                                       
3396         if (item == null) {                                                                              
3397             if (LauncherAppState.isDogfoodBuild()) {                                                     
3398                 throw new NullPointerException("DragObject has null info");                              
3399             }                                                                                            
3400             return;                                                                                      
3401         }                                                                                                
3402         // Ensure that we have proper spans for the item that we are dropping                            
3403         if ((item.spanX < 0) || (item.spanY < 0)) {                                                      
3404             throw new RuntimeException("Improper spans found");                                          
3405         }                                                                                                
3406         mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, d.dragView, mDrag🔵
3407         final View child = (mDragInfo == null) ? null : mDragInfo.cell;                                  
3408         // Identify whether we have dragged over a side page                                             
3409         if (workspaceInModalState()) {                                                                   
3410             if ((mLauncher.getHotseat() != null) && (!isExternalDragWidget(d))) {                        
3411                 if (isPointInSelfOverHotseat(d.x, d.y, r)) {                                             
3412                     layout = mLauncher.getHotseat().getLayout();                                         
3413                 }                                                                                        
3414             }                                                                                            
3415             if (layout == null) {                                                                        
3416                 layout = findMatchingPageForDragOver(d.dragView, d.x, d.y, false);                       
3417             }                                                                                            
3418             if (layout != mDragTargetLayout) {                                                           
3419                 setCurrentDropLayout(layout);                                                            
3420                 setCurrentDragOverlappingLayout(layout);                                                 
3421                 boolean isInSpringLoadedMode = mState == State.SPRING_LOADED;                            
3422                 if (isInSpringLoadedMode) {                                                              
3423                     if (mLauncher.isHotseatLayout(layout)) {                                             
3424                         mSpringLoadedDragController.cancel();                                            
3425                     } else {                                                                             
3426                         mSpringLoadedDragController.setAlarm(mDragTargetLayout);                         
3427                     }                                                                                    
3428                 }                                                                                        
3429             }                                                                                            
3430         } else {                                                                                         
3431             // Test to see if we are over the hotseat otherwise just use the current page                
3432             if ((mLauncher.getHotseat() != null) && (!isDragWidget(d))) {                                
3433                 if (isPointInSelfOverHotseat(d.x, d.y, r)) {                                             
3434                     layout = mLauncher.getHotseat().getLayout();                                         
3435                 }                                                                                        
3436             }                                                                                            
3437             if (layout == null) {                                                                        
3438                 layout = getCurrentDropLayout();                                                         
3439             }                                                                                            
3440             if (layout != mDragTargetLayout) {                                                           
3441                 setCurrentDropLayout(layout);                                                            
3442                 setCurrentDragOverlappingLayout(layout);                                                 
3443             }                                                                                            
3444         }                                                                                                
3445         // Handle the drag over                                                                          
3446         if (mDragTargetLayout != null) {                                                                 
3447             // We want the point to be mapped to the dragTarget.                                         
3448             if (mLauncher.isHotseatLayout(mDragTargetLayout)) {                                          
3449                 mapPointFromSelfToHotseatLayout(mLauncher.getHotseat(), mDragViewVisualCenter);          
3450             } else {                                                                                     
3451                 mapPointFromSelfToChild(mDragTargetLayout, mDragViewVisualCenter, null);                 
3452             }                                                                                            
3453             ItemInfo info = ((ItemInfo) (d.dragInfo));                                                   
3454             int minSpanX = item.spanX;                                                                   
3455             int minSpanY = item.spanY;                                                                   
3456             if ((item.minSpanX > 0) && (item.minSpanY > 0)) {                                            
3457                 minSpanX = item.minSpanX;                                                                
3458                 minSpanY = item.minSpanY;                                                                
3459             }                                                                                            
3460             mTargetCell = findNearestArea(((int) (mDragViewVisualCenter[0])), ((int) (mDragViewVisualCent🔵
3461             int reorderX = mTargetCell[0];                                                               
3462             int reorderY = mTargetCell[1];                                                               
3463             setCurrentDropOverCell(mTargetCell[0], mTargetCell[1]);                                      
3464             float targetCellDistance = mDragTargetLayout.getDistanceFromCell(mDragViewVisualCenter[0], mD🔵
3465             final View dragOverView = mDragTargetLayout.getChildAt(mTargetCell[0], mTargetCell[1]);      
3466             manageFolderFeedback(info, mDragTargetLayout, mTargetCell, targetCellDistance, dragOverView);
3467             boolean nearestDropOccupied = mDragTargetLayout.isNearestDropLocationOccupied(((int) (mDragVi🔵
3468             if (!nearestDropOccupied) {                                                                  
3469                 mDragTargetLayout.visualizeDropLocation(child, mDragOutline, ((int) (mDragViewVisualCente🔵
3470             } else if ((((mDragMode == DRAG_MODE_NONE) || (mDragMode == DRAG_MODE_REORDER)) && (!mReorder🔵
3471                 int[] resultSpan = new int[2];                                                           
3472                 mDragTargetLayout.performReorder(((int) (mDragViewVisualCenter[0])), ((int) (mDragViewVis🔵
3473                 // Otherwise, if we aren't adding to or creating a folder and there's no pending         
3474                 // reorder, then we schedule a reorder                                                   
3475                 ReorderAlarmListener listener = new ReorderAlarmListener(mDragViewVisualCenter, minSpanX,🔵
3476                 mReorderAlarm.setOnAlarmListener(listener);                                              
3477                 mReorderAlarm.setAlarm(REORDER_TIMEOUT);                                                 
3478             }                                                                                            
3479             if (((mDragMode == DRAG_MODE_CREATE_FOLDER) || (mDragMode == DRAG_MODE_ADD_TO_FOLDER)) || (!n🔵
3480                 if (mDragTargetLayout != null) {                                                         
3481                     mDragTargetLayout.revertTempState();                                                 
3482                 }                                                                                        
3483             }                                                                                            
3484         }                                                                                                
3485     }                                                                                                    
3486                                                                                                          
3487     private void manageFolderFeedback(ItemInfo info, CellLayout targetLayout,                            
3488             int[] targetCell, float distance, View dragOverView) {                                       
3489         boolean userFolderPending = willCreateUserFolder(info, targetLayout, targetCell, distance,       
3490                 false);                                                                                  
3491                                                                                                          
3492         if (mDragMode == DRAG_MODE_NONE && userFolderPending &&                                          
3493                 !mFolderCreationAlarm.alarmPending()) {                                                  
3494             mFolderCreationAlarm.setOnAlarmListener(new                                                  
3495                     FolderCreationAlarmListener(targetLayout, targetCell[0], targetCell[1]));            
3496             mFolderCreationAlarm.setAlarm(FOLDER_CREATION_TIMEOUT);                                      
3497             return;                                                                                      
3498         }                                                                                                
3499                                                                                                          
3500         boolean willAddToFolder =                                                                        
3501                 willAddToExistingUserFolder(info, targetLayout, targetCell, distance);                   
3502                                                                                                          
3503         if (willAddToFolder && mDragMode == DRAG_MODE_NONE) {                                            
3504             mDragOverFolderIcon = ((FolderIcon) dragOverView);                                           
3505             mDragOverFolderIcon.onDragEnter(info);                                                       
3506             if (targetLayout != null) {                                                                  
3507                 targetLayout.clearDragOutlines();                                                        
3508             }                                                                                            
3509             setDragMode(DRAG_MODE_ADD_TO_FOLDER);                                                        
3510             return;                                                                                      
3511         }                                                                                                
3512                                                                                                          
3513         if (mDragMode == DRAG_MODE_ADD_TO_FOLDER && !willAddToFolder) {                                  
3514             setDragMode(DRAG_MODE_NONE);                                                                 
3515         }                                                                                                
3516         if (mDragMode == DRAG_MODE_CREATE_FOLDER && !userFolderPending) {                                
3517             setDragMode(DRAG_MODE_NONE);                                                                 
3518         }                                                                                                
3519                                                                                                          
3520         return;                                                                                          
3521     }                                                                                                    
3522                                                                                                          
3523     class FolderCreationAlarmListener implements OnAlarmListener {                                       
3524         CellLayout layout;                                                                               
3525                                                                                                          
3526         int cellX;                                                                                       
3527                                                                                                          
3528         int cellY;                                                                                       
3529                                                                                                          
3530         public FolderCreationAlarmListener(CellLayout layout, int cellX, int cellY) {                    
3531             this.layout = layout;                                                                        
3532             this.cellX = cellX;                                                                          
3533             this.cellY = cellY;                                                                          
3534         }                                                                                                
3535                                                                                                          
3536         public void onAlarm(Alarm alarm) {                                                               
3537             if (mDragFolderRingAnimator != null) {                                                       
3538                 // This shouldn't happen ever, but just in case, make sure we clean up the mess.         
3539                 mDragFolderRingAnimator.animateToNaturalState();                                         
3540             }                                                                                            
3541             mDragFolderRingAnimator = new FolderRingAnimator(mLauncher, null);                           
3542             mDragFolderRingAnimator.setCell(cellX, cellY);                                               
3543             mDragFolderRingAnimator.setCellLayout(layout);                                               
3544             mDragFolderRingAnimator.animateToAcceptState();                                              
3545             layout.showFolderAccept(mDragFolderRingAnimator);                                            
3546             layout.clearDragOutlines();                                                                  
3547             setDragMode(DRAG_MODE_CREATE_FOLDER);                                                        
3548         }                                                                                                
3549     }                                                                                                    
3550                                                                                                          
3551     class ReorderAlarmListener implements OnAlarmListener {                                              
3552         float[] dragViewCenter;                                                                          
3553                                                                                                          
3554         int minSpanX;                                                                                    
3555                                                                                                          
3556         int minSpanY;                                                                                    
3557                                                                                                          
3558         int spanX;                                                                                       
3559                                                                                                          
3560         int spanY;                                                                                       
3561                                                                                                          
3562         DragView dragView;                                                                               
3563                                                                                                          
3564         View child;                                                                                      
3565                                                                                                          
3566         public ReorderAlarmListener(float[] dragViewCenter, int minSpanX, int minSpanY, int spanX, int sp🔵
3567             this.dragViewCenter = dragViewCenter;                                                        
3568             this.minSpanX = minSpanX;                                                                    
3569             this.minSpanY = minSpanY;                                                                    
3570             this.spanX = spanX;                                                                          
3571             this.spanY = spanY;                                                                          
3572             this.child = child;                                                                          
3573             this.dragView = dragView;                                                                    
3574         }                                                                                                
3575                                                                                                          
3576         public void onAlarm(Alarm alarm) {                                                               
3577             int[] resultSpan = new int[2];                                                               
3578             mTargetCell = findNearestArea(((int) (mDragViewVisualCenter[0])), ((int) (mDragViewVisualCent🔵
3579             mLastReorderX = mTargetCell[0];                                                              
3580             mLastReorderY = mTargetCell[1];                                                              
3581             mTargetCell = mDragTargetLayout.performReorder(((int) (mDragViewVisualCenter[0])), ((int) (mD🔵
3582             if ((mTargetCell[0] < 0) || (mTargetCell[1] < 0)) {                                          
3583                 mDragTargetLayout.revertTempState();                                                     
3584             } else {                                                                                     
3585                 setDragMode(DRAG_MODE_REORDER);                                                          
3586             }                                                                                            
3587             boolean resize = (resultSpan[0] != spanX) || (resultSpan[1] != spanY);                       
3588             mDragTargetLayout.visualizeDropLocation(child, mDragOutline, ((int) (mDragViewVisualCenter[0]🔵
3589         }                                                                                                
3590     }                                                                                                    
3591                                                                                                          
3592     @Override                                                                                            
3593     public void getHitRectRelativeToDragLayer(Rect outRect) {                                            
3594         // We want the workspace to have the whole area of the display (it will find the correct         
3595         // cell layout to drop to in the existing drag/drop logic.                                       
3596         mLauncher.getDragLayer().getDescendantRectRelativeToSelf(this, outRect);                         
3597     }                                                                                                    
3598                                                                                                          
3599     /**                                                                                                  
3600      * Add the item specified by dragInfo to the given layout.                                           
3601      * @return true if successful                                                                        
3602      */                                                                                                  
3603     public boolean addExternalItemToScreen(ItemInfo dragInfo, CellLayout layout) {                       
3604         if (layout.findCellForSpan(mTempEstimate, dragInfo.spanX, dragInfo.spanY)) {                     
3605             onDropExternal(dragInfo.dropPos, (ItemInfo) dragInfo, (CellLayout) layout, false);           
3606             return true;                                                                                 
3607         }                                                                                                
3608         mLauncher.showOutOfSpaceMessage(mLauncher.isHotseatLayout(layout));                              
3609         return false;                                                                                    
3610     }                                                                                                    
3611                                                                                                          
3612     private void onDropExternal(int[] touchXY, Object dragInfo,                                          
3613             CellLayout cellLayout, boolean insertAtFirst) {                                              
3614         onDropExternal(touchXY, dragInfo, cellLayout, insertAtFirst, null);                              
3615     }                                                                                                    
3616                                                                                                          
3617     /**                                                                                                  
3618      * Drop an item that didn't originate on one of the workspace screens.                               
3619      * It may have come from Launcher (e.g. from all apps or customize), or it may have                  
3620      * come from another app altogether.                                                                 
3621      *                                                                                                   
3622      * NOTE: This can also be called when we are outside of a drag event, when we want                   
3623      * to add an item to one of the workspace screens.                                                   
3624      */                                                                                                  
3625     private void onDropExternal(final int[] touchXY, final Object dragInfo, final CellLayout cellLayout, 🔵
3626         final Runnable exitSpringLoadedRunnable = new Runnable() {                                       
3627             @Override                                                                                    
3628             public void run() {                                                                          
3629                 mLauncher.exitSpringLoadedDragModeDelayed(true, Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIM🔵
3630             }                                                                                            
3631         };                                                                                               
3632         ItemInfo info = ((ItemInfo) (dragInfo));                                                         
3633         int spanX = info.spanX;                                                                          
3634         int spanY = info.spanY;                                                                          
3635         if (mDragInfo != null) {                                                                         
3636             spanX = mDragInfo.spanX;                                                                     
3637             spanY = mDragInfo.spanY;                                                                     
3638         }                                                                                                
3639         final long container = (mLauncher.isHotseatLayout(cellLayout)) ? Favorites.CONTAINER_HOTSEAT : Fa🔵
3640         final long screenId = getIdForScreen(cellLayout);                                                
3641         if (((!mLauncher.isHotseatLayout(cellLayout)) && (screenId != getScreenIdForPageIndex(mCurrentPag🔵
3642             snapToScreenId(screenId, null);                                                              
3643         }                                                                                                
3644         if (info instanceof PendingAddItemInfo) {                                                        
3645             final PendingAddItemInfo pendingInfo = ((PendingAddItemInfo) (dragInfo));                    
3646             boolean findNearestVacantCell = true;                                                        
3647             if (pendingInfo.itemType == Favorites.ITEM_TYPE_SHORTCUT) {                                  
3648                 mTargetCell = findNearestArea(((int) (touchXY[0])), ((int) (touchXY[1])), spanX, spanY, c🔵
3649                 float distance = cellLayout.getDistanceFromCell(mDragViewVisualCenter[0], mDragViewVisual🔵
3650                 if (willCreateUserFolder(((ItemInfo) (d.dragInfo)), cellLayout, mTargetCell, distance, tr🔵
3651                     findNearestVacantCell = false;                                                       
3652                 }                                                                                        
3653             }                                                                                            
3654             final ItemInfo item = ((ItemInfo) (d.dragInfo));                                             
3655             boolean updateWidgetSize = false;                                                            
3656             if (findNearestVacantCell) {                                                                 
3657                 int minSpanX = item.spanX;                                                               
3658                 int minSpanY = item.spanY;                                                               
3659                 if ((item.minSpanX > 0) && (item.minSpanY > 0)) {                                        
3660                     minSpanX = item.minSpanX;                                                            
3661                     minSpanY = item.minSpanY;                                                            
3662                 }                                                                                        
3663                 int[] resultSpan = new int[2];                                                           
3664                 mTargetCell = cellLayout.performReorder(((int) (mDragViewVisualCenter[0])), ((int) (mDrag🔵
3665                 if ((resultSpan[0] != item.spanX) || (resultSpan[1] != item.spanY)) {                    
3666                     updateWidgetSize = true;                                                             
3667                 }                                                                                        
3668                 item.spanX = resultSpan[0];                                                              
3669                 item.spanY = resultSpan[1];                                                              
3670             }                                                                                            
3671             Runnable onAnimationCompleteRunnable = new Runnable() {                                      
3672                 @Override                                                                                
3673                 public void run() {                                                                      
3674                     // Normally removeExtraEmptyScreen is called in Workspace#onDragEnd, but when        
3675                     // adding an item that may not be dropped right away (due to a config activity)      
3676                     // we defer the removal until the activity returns.                                  
3677                     deferRemoveExtraEmptyScreen();                                                       
3678                     // When dragging and dropping from customization tray, we deal with creating         
3679                     // widgets/shortcuts/folders in a slightly different way                             
3680                     switch (pendingInfo.itemType) {                                                      
3681                         case Favorites.ITEM_TYPE_APPWIDGET :                                             
3682                             int[] span = new int[2];                                                     
3683                             span[0] = item.spanX;                                                        
3684                             span[1] = item.spanY;                                                        
3685                             mLauncher.addAppWidgetFromDrop(((PendingAddWidgetInfo) (pendingInfo)), contai🔵
3686                             break;                                                                       
3687                         case Favorites.ITEM_TYPE_SHORTCUT :                                              
3688                             mLauncher.processShortcutFromDrop(pendingInfo.componentName, container, scree🔵
3689                             break;                                                                       
3690                         default :                                                                        
3691                             throw new IllegalStateException("Unknown item type: " + pendingInfo.itemType)🔵
3692                     }                                                                                    
3693                 }                                                                                        
3694             };                                                                                           
3695             View finalView = (pendingInfo.itemType == Favorites.ITEM_TYPE_APPWIDGET) ? ((PendingAddWidget🔵
3696             if ((finalView instanceof AppWidgetHostView) && updateWidgetSize) {                          
3697                 AppWidgetHostView awhv = ((AppWidgetHostView) (finalView));                              
3698                 AppWidgetResizeFrame.updateWidgetSizeRanges(awhv, mLauncher, item.spanX, item.spanY);    
3699             }                                                                                            
3700             int animationStyle = ANIMATE_INTO_POSITION_AND_DISAPPEAR;                                    
3701             if ((pendingInfo.itemType == Favorites.ITEM_TYPE_APPWIDGET) && (((PendingAddWidgetInfo) (pend🔵
3702                 animationStyle = ANIMATE_INTO_POSITION_AND_REMAIN;                                       
3703             }                                                                                            
3704             animateWidgetDrop(info, cellLayout, d.dragView, onAnimationCompleteRunnable, animationStyle, 🔵
3705         } else {                                                                                         
3706             // This is for other drag/drop cases, like dragging from All Apps                            
3707             View view = null;                                                                            
3708             switch (info.itemType) {                                                                     
3709                 case Favorites.ITEM_TYPE_APPLICATION :                                                   
3710                 case Favorites.ITEM_TYPE_SHORTCUT :                                                      
3711                     if ((info.container == NO_ID) && (info instanceof AppInfo)) {                        
3712                         // Came from all apps -- make a copy                                             
3713                         info = new ShortcutInfo(((AppInfo) (info)));                                     
3714                     }                                                                                    
3715                     view = mLauncher.createShortcut(R.layout.application, cellLayout, ((ShortcutInfo) (in🔵
3716                     break;                                                                               
3717                 case Favorites.ITEM_TYPE_FOLDER :                                                        
3718                     view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher, cellLayout, ((FolderInfo) 🔵
3719                     break;                                                                               
3720                 default :                                                                                
3721                     throw new IllegalStateException("Unknown item type: " + info.itemType);              
3722             }                                                                                            
3723             // First we find the cell nearest to point at which the item is                              
3724             // dropped, without any consideration to whether there is an item there.                     
3725             if (touchXY != null) {                                                                       
3726                 mTargetCell = findNearestArea(((int) (touchXY[0])), ((int) (touchXY[1])), spanX, spanY, c🔵
3727                 float distance = cellLayout.getDistanceFromCell(mDragViewVisualCenter[0], mDragViewVisual🔵
3728                 d.postAnimationRunnable = exitSpringLoadedRunnable;                                      
3729                 if (createUserFolderIfNecessary(view, container, cellLayout, mTargetCell, distance, true,🔵
3730                     return;                                                                              
3731                 }                                                                                        
3732                 if (addToExistingFolderIfNecessary(view, cellLayout, mTargetCell, distance, d, true)) {  
3733                     return;                                                                              
3734                 }                                                                                        
3735             }                                                                                            
3736             if (touchXY != null) {                                                                       
3737                 // when dragging and dropping, just find the closest free spot                           
3738                 mTargetCell = cellLayout.performReorder(((int) (mDragViewVisualCenter[0])), ((int) (mDrag🔵
3739             } else {                                                                                     
3740                 cellLayout.findCellForSpan(mTargetCell, 1, 1);                                           
3741             }                                                                                            
3742             // Add the item to DB before adding to screen ensures that the container and other           
3743             // values of the info is properly updated.                                                   
3744             LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screenId, mTargetCell[0], m🔵
3745             addInScreen(view, container, screenId, mTargetCell[0], mTargetCell[1], info.spanX, info.spanY🔵
3746             cellLayout.onDropChild(view);                                                                
3747             cellLayout.getShortcutsAndWidgets().measureChild(view);                                      
3748             if (d.dragView != null) {                                                                    
3749                 // We wrap the animation call in the temporary set and reset of the current              
3750                 // cellLayout to its final transform -- this means we animate the drag view to           
3751                 // the correct final location.                                                           
3752                 setFinalTransitionTransform(cellLayout);                                                 
3753                 mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, view, exitSpringLoadedRunnab🔵
3754                 resetTransitionTransform(cellLayout);                                                    
3755             }                                                                                            
3756         }                                                                                                
3757     }                                                                                                    
3758                                                                                                          
3759     public Bitmap createWidgetBitmap(ItemInfo widgetInfo, View layout) {                                 
3760         int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(widgetInfo.spanX, widgetInfo.spanY🔵
3761         int visibility = layout.getVisibility();                                                         
3762         layout.setVisibility(VISIBLE);                                                                   
3763         int width = MeasureSpec.makeMeasureSpec(unScaledSize[0], MeasureSpec.EXACTLY);                   
3764         int height = MeasureSpec.makeMeasureSpec(unScaledSize[1], MeasureSpec.EXACTLY);                  
3765         Bitmap b = Bitmap.createBitmap(unScaledSize[0], unScaledSize[1], Bitmap.Config.ARGB_8888);       
3766         mCanvas.setBitmap(b);                                                                            
3767         layout.measure(width, height);                                                                   
3768         layout.layout(0, 0, unScaledSize[0], unScaledSize[1]);                                           
3769         layout.draw(mCanvas);                                                                            
3770         mCanvas.setBitmap(null);                                                                         
3771         layout.setVisibility(visibility);                                                                
3772         return b;                                                                                        
3773     }                                                                                                    
3774                                                                                                          
3775     private void getFinalPositionForDropAnimation(int[] loc, float[] scaleXY,                            
3776             DragView dragView, CellLayout layout, ItemInfo info, int[] targetCell,                       
3777             boolean external, boolean scale) {                                                           
3778         // Now we animate the dragView, (ie. the widget or shortcut preview) into its final              
3779         // location and size on the home screen.                                                         
3780         int spanX = info.spanX;                                                                          
3781         int spanY = info.spanY;                                                                          
3782                                                                                                          
3783         Rect r = estimateItemPosition(layout, info, targetCell[0], targetCell[1], spanX, spanY);         
3784         loc[0] = r.left;                                                                                 
3785         loc[1] = r.top;                                                                                  
3786                                                                                                          
3787         setFinalTransitionTransform(layout);                                                             
3788         float cellLayoutScale =                                                                          
3789                 mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(layout, loc, true);            
3790         resetTransitionTransform(layout);                                                                
3791                                                                                                          
3792         float dragViewScaleX;                                                                            
3793         float dragViewScaleY;                                                                            
3794         if (scale) {                                                                                     
3795             dragViewScaleX = (1.0f * r.width()) / dragView.getMeasuredWidth();                           
3796             dragViewScaleY = (1.0f * r.height()) / dragView.getMeasuredHeight();                         
3797         } else {                                                                                         
3798             dragViewScaleX = 1f;                                                                         
3799             dragViewScaleY = 1f;                                                                         
3800         }                                                                                                
3801                                                                                                          
3802         // The animation will scale the dragView about its center, so we need to center about            
3803         // the final location.                                                                           
3804         loc[0] -= (dragView.getMeasuredWidth() - cellLayoutScale * r.width()) / 2;                       
3805         loc[1] -= (dragView.getMeasuredHeight() - cellLayoutScale * r.height()) / 2;                     
3806                                                                                                          
3807         scaleXY[0] = dragViewScaleX * cellLayoutScale;                                                   
3808         scaleXY[1] = dragViewScaleY * cellLayoutScale;                                                   
3809     }                                                                                                    
3810                                                                                                          
3811     public void animateWidgetDrop(ItemInfo info, CellLayout cellLayout, DragView dragView,               
3812             final Runnable onCompleteRunnable, int animationType, final View finalView,                  
3813             boolean external) {                                                                          
3814         Rect from = new Rect();                                                                          
3815         mLauncher.getDragLayer().getViewRectRelativeToSelf(dragView, from);                              
3816                                                                                                          
3817         int[] finalPos = new int[2];                                                                     
3818         float scaleXY[] = new float[2];                                                                  
3819         boolean scalePreview = !(info instanceof PendingAddShortcutInfo);                                
3820         getFinalPositionForDropAnimation(finalPos, scaleXY, dragView, cellLayout, info, mTargetCell,     
3821                 external, scalePreview);                                                                 
3822                                                                                                          
3823         Resources res = mLauncher.getResources();                                                        
3824         final int duration = res.getInteger(R.integer.config_dropAnimMaxDuration) - 200;                 
3825                                                                                                          
3826         // In the case where we've prebound the widget, we remove it from the DragLayer                  
3827         if (finalView instanceof AppWidgetHostView && external) {                                        
3828             Log.d(TAG, "6557954 Animate widget drop, final view is appWidgetHostView");                  
3829             mLauncher.getDragLayer().removeView(finalView);                                              
3830         }                                                                                                
3831         if ((animationType == ANIMATE_INTO_POSITION_AND_RESIZE || external) && finalView != null) {      
3832             Bitmap crossFadeBitmap = createWidgetBitmap(info, finalView);                                
3833             dragView.setCrossFadeBitmap(crossFadeBitmap);                                                
3834             dragView.crossFade((int) (duration * 0.8f));                                                 
3835         } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET && external) {        
3836             scaleXY[0] = scaleXY[1] = Math.min(scaleXY[0],  scaleXY[1]);                                 
3837         }                                                                                                
3838                                                                                                          
3839         DragLayer dragLayer = mLauncher.getDragLayer();                                                  
3840         if (animationType == CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION) {                                   
3841             mLauncher.getDragLayer().animateViewIntoPosition(dragView, finalPos, 0f, 0.1f, 0.1f,         
3842                     DragLayer.ANIMATION_END_DISAPPEAR, onCompleteRunnable, duration);                    
3843         } else {                                                                                         
3844             int endStyle;                                                                                
3845             if (animationType == ANIMATE_INTO_POSITION_AND_REMAIN) {                                     
3846                 endStyle = DragLayer.ANIMATION_END_REMAIN_VISIBLE;                                       
3847             } else {                                                                                     
3848                 endStyle = DragLayer.ANIMATION_END_DISAPPEAR;;                                           
3849             }                                                                                            
3850                                                                                                          
3851             Runnable onComplete = new Runnable() {                                                       
3852                 @Override                                                                                
3853                 public void run() {                                                                      
3854                     if (finalView != null) {                                                             
3855                         finalView.setVisibility(VISIBLE);                                                
3856                     }                                                                                    
3857                     if (onCompleteRunnable != null) {                                                    
3858                         onCompleteRunnable.run();                                                        
3859                     }                                                                                    
3860                 }                                                                                        
3861             };                                                                                           
3862             dragLayer.animateViewIntoPosition(dragView, from.left, from.top, finalPos[0],                
3863                     finalPos[1], 1, 1, 1, scaleXY[0], scaleXY[1], onComplete, endStyle,                  
3864                     duration, this);                                                                     
3865         }                                                                                                
3866     }                                                                                                    
3867                                                                                                          
3868     public void setFinalTransitionTransform(CellLayout layout) {                                         
3869         if (isSwitchingState()) {                                                                        
3870             mCurrentScale = getScaleX();                                                                 
3871             setScaleX(mNewScale);                                                                        
3872             setScaleY(mNewScale);                                                                        
3873         }                                                                                                
3874     }                                                                                                    
3875                                                                                                          
3876     public void resetTransitionTransform(CellLayout layout) {                                            
3877         if (isSwitchingState()) {                                                                        
3878             setScaleX(mCurrentScale);                                                                    
3879             setScaleY(mCurrentScale);                                                                    
3880         }                                                                                                
3881     }                                                                                                    
3882                                                                                                          
3883     /**                                                                                                  
3884      * Return the current {@link CellLayout}, correctly picking the destination                          
3885      * screen while a scroll is in progress.                                                             
3886      */                                                                                                  
3887     public CellLayout getCurrentDropLayout() {                                                           
3888         return (CellLayout) getChildAt(getNextPage());                                                   
3889     }                                                                                                    
3890                                                                                                          
3891     /**                                                                                                  
3892      * Return the current CellInfo describing our current drag; this method exists                       
3893      * so that Launcher can sync this object with the correct info when the activity is created/         
3894      * destroyed                                                                                         
3895      *                                                                                                   
3896      */                                                                                                  
3897     public CellLayout.CellInfo getDragInfo() {                                                           
3898         return mDragInfo;                                                                                
3899     }                                                                                                    
3900                                                                                                          
3901     public int getCurrentPageOffsetFromCustomContent() {                                                 
3902         return getNextPage() - numCustomPages();                                                         
3903     }                                                                                                    
3904                                                                                                          
3905     /**                                                                                                  
3906      * Calculate the nearest cell where the given object would be dropped.                               
3907      *                                                                                                   
3908      * pixelX and pixelY should be in the coordinate system of layout                                    
3909      */                                                                                                  
3910     private int[] findNearestArea(int pixelX, int pixelY,                                                
3911             int spanX, int spanY, CellLayout layout, int[] recycle) {                                    
3912         return layout.findNearestArea(                                                                   
3913                 pixelX, pixelY, spanX, spanY, recycle);                                                  
3914     }                                                                                                    
3915                                                                                                          
3916     void setup(DragController dragController) {                                                          
3917         mSpringLoadedDragController = new SpringLoadedDragController(mLauncher);                         
3918         mDragController = dragController;                                                                
3919                                                                                                          
3920         // hardware layers on children are enabled on startup, but should be disabled until              
3921         // needed                                                                                        
3922         updateChildrenLayersEnabled(false);                                                              
3923     }                                                                                                    
3924                                                                                                          
3925     /**                                                                                                  
3926      * Called at the end of a drag which originated on the workspace.                                    
3927      */                                                                                                  
3928     public void onDropCompleted(final View target, final DragObject d, final boolean isFlingToDelete, fin🔵
3929         if (mDeferDropAfterUninstall) {                                                                  
3930             mDeferredAction = new Runnable() {                                                           
3931                 public void run() {                                                                      
3932                     onDropCompleted(target, d, isFlingToDelete, success);                                
3933                     mDeferredAction = null;                                                              
3934                 }                                                                                        
3935             };                                                                                           
3936             return;                                                                                      
3937         }                                                                                                
3938         boolean beingCalledAfterUninstall = mDeferredAction != null;                                     
3939         if (success && (!(beingCalledAfterUninstall && (!mUninstallSuccessful)))) {                      
3940             if ((target != this) && (mDragInfo != null)) {                                               
3941                 CellLayout parentCell = getParentCellLayoutForView(mDragInfo.cell);                      
3942                 if (parentCell != null) {                                                                
3943                     parentCell.removeView(mDragInfo.cell);                                               
3944                 } else if (LauncherAppState.isDogfoodBuild()) {                                          
3945                     throw new NullPointerException("mDragInfo.cell has null parent");                    
3946                 }                                                                                        
3947                 if (mDragInfo.cell instanceof DropTarget) {                                              
3948                     mDragController.removeDropTarget(((DropTarget) (mDragInfo.cell)));                   
3949                 }                                                                                        
3950             }                                                                                            
3951         } else if (mDragInfo != null) {                                                                  
3952             CellLayout cellLayout;                                                                       
3953             if (mLauncher.isHotseatLayout(target)) {                                                     
3954                 cellLayout = mLauncher.getHotseat().getLayout();                                         
3955             } else {                                                                                     
3956                 cellLayout = getScreenWithId(mDragInfo.screenId);                                        
3957             }                                                                                            
3958             if ((cellLayout == null) && LauncherAppState.isDogfoodBuild()) {                             
3959                 throw new RuntimeException("Invalid state: cellLayout == null in " + "Workspace#onDropCom🔵
3960             }                                                                                            
3961             if (cellLayout != null) {                                                                    
3962                 cellLayout.onDropChild(mDragInfo.cell);                                                  
3963             }                                                                                            
3964         }                                                                                                
3965         if ((d.cancelled || (beingCalledAfterUninstall && (!mUninstallSuccessful))) && (mDragInfo.cell !=🔵
3966             mDragInfo.cell.setVisibility(VISIBLE);                                                       
3967         }                                                                                                
3968         mDragOutline = null;                                                                             
3969         mDragInfo = null;                                                                                
3970     }                                                                                                    
3971                                                                                                          
3972     public void deferCompleteDropAfterUninstallActivity() {                                              
3973         mDeferDropAfterUninstall = true;                                                                 
3974     }                                                                                                    
3975                                                                                                          
3976     /// maybe move this into a smaller part                                                              
3977     public void onUninstallActivityReturned(boolean success) {                                           
3978         mDeferDropAfterUninstall = false;                                                                
3979         mUninstallSuccessful = success;                                                                  
3980         if (mDeferredAction != null) {                                                                   
3981             mDeferredAction.run();                                                                       
3982         }                                                                                                
3983     }                                                                                                    
3984                                                                                                          
3985     void updateItemLocationsInDatabase(CellLayout cl) {                                                  
3986         int count = cl.getShortcutsAndWidgets().getChildCount();                                         
3987                                                                                                          
3988         long screenId = getIdForScreen(cl);                                                              
3989         int container = Favorites.CONTAINER_DESKTOP;                                                     
3990                                                                                                          
3991         if (mLauncher.isHotseatLayout(cl)) {                                                             
3992             screenId = -1;                                                                               
3993             container = Favorites.CONTAINER_HOTSEAT;                                                     
3994         }                                                                                                
3995                                                                                                          
3996         for (int i = 0; i < count; i++) {                                                                
3997             View v = cl.getShortcutsAndWidgets().getChildAt(i);                                          
3998             ItemInfo info = (ItemInfo) v.getTag();                                                       
3999             // Null check required as the AllApps button doesn't have an item info                       
4000             if (info != null && info.requiresDbUpdate) {                                                 
4001                 info.requiresDbUpdate = false;                                                           
4002                 LauncherModel.modifyItemInDatabase(mLauncher, info, container, screenId, info.cellX,     
4003                         info.cellY, info.spanX, info.spanY);                                             
4004             }                                                                                            
4005         }                                                                                                
4006     }                                                                                                    
4007                                                                                                          
4008     ArrayList<ComponentName> getUniqueComponents(boolean stripDuplicates, ArrayList<ComponentName> duplic🔵
4009         ArrayList<ComponentName> uniqueIntents = new ArrayList<ComponentName>();                         
4010         getUniqueIntents((CellLayout) mLauncher.getHotseat().getLayout(), uniqueIntents, duplicates, fals🔵
4011         int count = getChildCount();                                                                     
4012         for (int i = 0; i < count; i++) {                                                                
4013             CellLayout cl = (CellLayout) getChildAt(i);                                                  
4014             getUniqueIntents(cl, uniqueIntents, duplicates, false);                                      
4015         }                                                                                                
4016         return uniqueIntents;                                                                            
4017     }                                                                                                    
4018                                                                                                          
4019     void getUniqueIntents(CellLayout cl, ArrayList<ComponentName> uniqueIntents,                         
4020             ArrayList<ComponentName> duplicates, boolean stripDuplicates) {                              
4021         int count = cl.getShortcutsAndWidgets().getChildCount();                                         
4022                                                                                                          
4023         ArrayList<View> children = new ArrayList<View>();                                                
4024         for (int i = 0; i < count; i++) {                                                                
4025             View v = cl.getShortcutsAndWidgets().getChildAt(i);                                          
4026             children.add(v);                                                                             
4027         }                                                                                                
4028                                                                                                          
4029         for (int i = 0; i < count; i++) {                                                                
4030             View v = children.get(i);                                                                    
4031             ItemInfo info = (ItemInfo) v.getTag();                                                       
4032             // Null check required as the AllApps button doesn't have an item info                       
4033             if (info instanceof ShortcutInfo) {                                                          
4034                 ShortcutInfo si = (ShortcutInfo) info;                                                   
4035                 ComponentName cn = si.intent.getComponent();                                             
4036                                                                                                          
4037                 Uri dataUri = si.intent.getData();                                                       
4038                 // If dataUri is not null / empty or if this component isn't one that would              
4039                 // have previously showed up in the AllApps list, then this is a widget-type             
4040                 // shortcut, so ignore it.                                                               
4041                 if (dataUri != null && !dataUri.equals(Uri.EMPTY)) {                                     
4042                     continue;                                                                            
4043                 }                                                                                        
4044                                                                                                          
4045                 if (!uniqueIntents.contains(cn)) {                                                       
4046                     uniqueIntents.add(cn);                                                               
4047                 } else {                                                                                 
4048                     if (stripDuplicates) {                                                               
4049                         cl.removeViewInLayout(v);                                                        
4050                         LauncherModel.deleteItemFromDatabase(mLauncher, si);                             
4051                     }                                                                                    
4052                     if (duplicates != null) {                                                            
4053                         duplicates.add(cn);                                                              
4054                     }                                                                                    
4055                 }                                                                                        
4056             }                                                                                            
4057             if (v instanceof FolderIcon) {                                                               
4058                 FolderIcon fi = (FolderIcon) v;                                                          
4059                 ArrayList<View> items = fi.getFolder().getItemsInReadingOrder();                         
4060                 for (int j = 0; j < items.size(); j++) {                                                 
4061                     if (items.get(j).getTag() instanceof ShortcutInfo) {                                 
4062                         ShortcutInfo si = (ShortcutInfo) items.get(j).getTag();                          
4063                         ComponentName cn = si.intent.getComponent();                                     
4064                                                                                                          
4065                         Uri dataUri = si.intent.getData();                                               
4066                         // If dataUri is not null / empty or if this component isn't one that would      
4067                         // have previously showed up in the AllApps list, then this is a widget-type     
4068                         // shortcut, so ignore it.                                                       
4069                         if (dataUri != null && !dataUri.equals(Uri.EMPTY)) {                             
4070                             continue;                                                                    
4071                         }                                                                                
4072                                                                                                          
4073                         if (!uniqueIntents.contains(cn)) {                                               
4074                             uniqueIntents.add(cn);                                                       
4075                         }  else {                                                                        
4076                             if (stripDuplicates) {                                                       
4077                                 fi.getFolderInfo().remove(si);                                           
4078                                 LauncherModel.deleteItemFromDatabase(mLauncher, si);                     
4079                             }                                                                            
4080                             if (duplicates != null) {                                                    
4081                                 duplicates.add(cn);                                                      
4082                             }                                                                            
4083                         }                                                                                
4084                     }                                                                                    
4085                 }                                                                                        
4086             }                                                                                            
4087         }                                                                                                
4088     }                                                                                                    
4089                                                                                                          
4090     void saveWorkspaceToDb() {                                                                           
4091         saveWorkspaceScreenToDb((CellLayout) mLauncher.getHotseat().getLayout());                        
4092         int count = getChildCount();                                                                     
4093         for (int i = 0; i < count; i++) {                                                                
4094             CellLayout cl = (CellLayout) getChildAt(i);                                                  
4095             saveWorkspaceScreenToDb(cl);                                                                 
4096         }                                                                                                
4097     }                                                                                                    
4098                                                                                                          
4099     void saveWorkspaceScreenToDb(CellLayout cl) {                                                        
4100         int count = cl.getShortcutsAndWidgets().getChildCount();                                         
4101                                                                                                          
4102         long screenId = getIdForScreen(cl);                                                              
4103         int container = Favorites.CONTAINER_DESKTOP;                                                     
4104                                                                                                          
4105         Hotseat hotseat = mLauncher.getHotseat();                                                        
4106         if (mLauncher.isHotseatLayout(cl)) {                                                             
4107             screenId = -1;                                                                               
4108             container = Favorites.CONTAINER_HOTSEAT;                                                     
4109         }                                                                                                
4110                                                                                                          
4111         for (int i = 0; i < count; i++) {                                                                
4112             View v = cl.getShortcutsAndWidgets().getChildAt(i);                                          
4113             ItemInfo info = (ItemInfo) v.getTag();                                                       
4114             // Null check required as the AllApps button doesn't have an item info                       
4115             if (info != null) {                                                                          
4116                 int cellX = info.cellX;                                                                  
4117                 int cellY = info.cellY;                                                                  
4118                 if (container == Favorites.CONTAINER_HOTSEAT) {                                          
4119                     cellX = hotseat.getCellXFromOrder((int) info.screenId);                              
4120                     cellY = hotseat.getCellYFromOrder((int) info.screenId);                              
4121                 }                                                                                        
4122                 LauncherModel.addItemToDatabase(mLauncher, info, container, screenId, cellX,             
4123                         cellY, false);                                                                   
4124             }                                                                                            
4125             if (v instanceof FolderIcon) {                                                               
4126                 FolderIcon fi = (FolderIcon) v;                                                          
4127                 fi.getFolder().addItemLocationsInDatabase();                                             
4128             }                                                                                            
4129         }                                                                                                
4130     }                                                                                                    
4131                                                                                                          
4132     @Override                                                                                            
4133     public float getIntrinsicIconScaleFactor() {                                                         
4134         return 1f;                                                                                       
4135     }                                                                                                    
4136                                                                                                          
4137     @Override                                                                                            
4138     public boolean supportsFlingToDelete() {                                                             
4139         return true;                                                                                     
4140     }                                                                                                    
4141                                                                                                          
4142     @Override                                                                                            
4143     public boolean supportsAppInfoDropTarget() {                                                         
4144         return false;                                                                                    
4145     }                                                                                                    
4146                                                                                                          
4147     @Override                                                                                            
4148     public boolean supportsDeleteDropTarget() {                                                          
4149         return true;                                                                                     
4150     }                                                                                                    
4151                                                                                                          
4152     @Override                                                                                            
4153     public void onFlingToDelete(DragObject d, int x, int y, PointF vec) {                                
4154         // Do nothing                                                                                    
4155     }                                                                                                    
4156                                                                                                          
4157     @Override                                                                                            
4158     public void onFlingToDeleteCompleted() {                                                             
4159         // Do nothing                                                                                    
4160     }                                                                                                    
4161                                                                                                          
4162     public boolean isDropEnabled() {                                                                     
4163         return true;                                                                                     
4164     }                                                                                                    
4165                                                                                                          
4166     @Override                                                                                            
4167     protected void onRestoreInstanceState(Parcelable state) {                                            
4168         super.onRestoreInstanceState(state);                                                             
4169         Launcher.setScreen(mCurrentPage);                                                                
4170     }                                                                                                    
4171                                                                                                          
4172     @Override                                                                                            
4173     protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {                     
4174         // We don't dispatch restoreInstanceState to our children using this code path.                  
4175         // Some pages will be restored immediately as their items are bound immediately, and             
4176         // others we will need to wait until after their items are bound.                                
4177         mSavedStates = container;                                                                        
4178     }                                                                                                    
4179                                                                                                          
4180     public void restoreInstanceStateForChild(int child) {                                                
4181         if (mSavedStates != null) {                                                                      
4182             mRestoredPages.add(child);                                                                   
4183             CellLayout cl = (CellLayout) getChildAt(child);                                              
4184             if (cl != null) {                                                                            
4185                 cl.restoreInstanceState(mSavedStates);                                                   
4186             }                                                                                            
4187         }                                                                                                
4188     }                                                                                                    
4189                                                                                                          
4190     public void restoreInstanceStateForRemainingPages() {                                                
4191         int count = getChildCount();                                                                     
4192         for (int i = 0; i < count; i++) {                                                                
4193             if (!mRestoredPages.contains(i)) {                                                           
4194                 restoreInstanceStateForChild(i);                                                         
4195             }                                                                                            
4196         }                                                                                                
4197         mRestoredPages.clear();                                                                          
4198         mSavedStates = null;                                                                             
4199     }                                                                                                    
4200                                                                                                          
4201     @Override                                                                                            
4202     public void scrollLeft() {                                                                           
4203         if ((!workspaceInModalState()) && (!mIsSwitchingState)) {                                        
4204             super.scrollLeft();                                                                          
4205         }                                                                                                
4206         Folder openFolder = getOpenFolder();                                                             
4207         if (openFolder != null) {                                                                        
4208             openFolder.completeDragExit();                                                               
4209         }                                                                                                
4210     }                                                                                                    
4211                                                                                                          
4212     @Override                                                                                            
4213     public void scrollRight() {                                                                          
4214         if ((!workspaceInModalState()) && (!mIsSwitchingState)) {                                        
4215             super.scrollRight();                                                                         
4216         }                                                                                                
4217         Folder openFolder = getOpenFolder();                                                             
4218         if (openFolder != null) {                                                                        
4219             openFolder.completeDragExit();                                                               
4220         }                                                                                                
4221     }                                                                                                    
4222                                                                                                          
4223     @Override                                                                                            
4224     public boolean onEnterScrollArea(int x, int y, int direction) {                                      
4225         // Ignore the scroll area if we are dragging over the hot seat                                   
4226         boolean isPortrait = !LauncherAppState.isScreenLandscape(getContext());                          
4227         if ((mLauncher.getHotseat() != null) && isPortrait) {                                            
4228             Rect r = new Rect();                                                                         
4229             mLauncher.getHotseat().getHitRect(r);                                                        
4230             if (r.contains(x, y)) {                                                                      
4231                 return false;                                                                            
4232             }                                                                                            
4233         }                                                                                                
4234         boolean result = false;                                                                          
4235         if (((!workspaceInModalState()) && (!mIsSwitchingState)) && (getOpenFolder() == null)) {         
4236             mInScrollArea = true;                                                                        
4237             final int page = getNextPage() + (direction == DragController.SCROLL_LEFT ? -1 : 1);         
4238             // We always want to exit the current layout to ensure parity of enter / exit                
4239             setCurrentDropLayout(null);                                                                  
4240             if ((0 <= page) && (page < getChildCount())) {                                               
4241                 // Ensure that we are not dragging over to the custom content screen                     
4242                 if (getScreenIdForPageIndex(page) == CUSTOM_CONTENT_SCREEN_ID) {                         
4243                     return false;                                                                        
4244                 }                                                                                        
4245                 CellLayout layout = ((CellLayout) (getChildAt(page)));                                   
4246                 setCurrentDragOverlappingLayout(layout);                                                 
4247                 // Workspace is responsible for drawing the edge glow on adjacent pages,                 
4248                 // so we need to redraw the workspace when this may have changed.                        
4249                 invalidate();                                                                            
4250                 result = true;                                                                           
4251             }                                                                                            
4252         }                                                                                                
4253         return result;                                                                                   
4254     }                                                                                                    
4255                                                                                                          
4256     @Override                                                                                            
4257     public boolean onExitScrollArea() {                                                                  
4258         boolean result = false;                                                                          
4259         if (mInScrollArea) {                                                                             
4260             invalidate();                                                                                
4261             CellLayout layout = getCurrentDropLayout();                                                  
4262             setCurrentDropLayout(layout);                                                                
4263             setCurrentDragOverlappingLayout(layout);                                                     
4264                                                                                                          
4265             result = true;                                                                               
4266             mInScrollArea = false;                                                                       
4267         }                                                                                                
4268         return result;                                                                                   
4269     }                                                                                                    
4270                                                                                                          
4271     private void onResetScrollArea() {                                                                   
4272         setCurrentDragOverlappingLayout(null);                                                           
4273         mInScrollArea = false;                                                                           
4274     }                                                                                                    
4275                                                                                                          
4276     /**                                                                                                  
4277      * Returns a specific CellLayout                                                                     
4278      */                                                                                                  
4279     CellLayout getParentCellLayoutForView(View v) {                                                      
4280         ArrayList<CellLayout> layouts = getWorkspaceAndHotseatCellLayouts();                             
4281         for (CellLayout layout : layouts) {                                                              
4282             if (layout.getShortcutsAndWidgets().indexOfChild(v) > -1) {                                  
4283                 return layout;                                                                           
4284             }                                                                                            
4285         }                                                                                                
4286         return null;                                                                                     
4287     }                                                                                                    
4288                                                                                                          
4289     /**                                                                                                  
4290      * Returns a list of all the CellLayouts in the workspace.                                           
4291      */                                                                                                  
4292     ArrayList<CellLayout> getWorkspaceAndHotseatCellLayouts() {                                          
4293         ArrayList<CellLayout> layouts = new ArrayList<CellLayout>();                                     
4294         int screenCount = getChildCount();                                                               
4295         for (int screen = 0; screen < screenCount; screen++) {                                           
4296             layouts.add(((CellLayout) getChildAt(screen)));                                              
4297         }                                                                                                
4298         if (mLauncher.getHotseat() != null) {                                                            
4299             layouts.add(mLauncher.getHotseat().getLayout());                                             
4300         }                                                                                                
4301         return layouts;                                                                                  
4302     }                                                                                                    
4303                                                                                                          
4304     /**                                                                                                  
4305      * We should only use this to search for specific children.  Do not use this method to modify        
4306      * ShortcutsAndWidgetsContainer directly. Includes ShortcutAndWidgetContainers from                  
4307      * the hotseat and workspace pages                                                                   
4308      */                                                                                                  
4309     ArrayList<ShortcutAndWidgetContainer> getAllShortcutAndWidgetContainers() {                          
4310         ArrayList<ShortcutAndWidgetContainer> childrenLayouts =                                          
4311                 new ArrayList<ShortcutAndWidgetContainer>();                                             
4312         int screenCount = getChildCount();                                                               
4313         for (int screen = 0; screen < screenCount; screen++) {                                           
4314             childrenLayouts.add(((CellLayout) getChildAt(screen)).getShortcutsAndWidgets());             
4315         }                                                                                                
4316         if (mLauncher.getHotseat() != null) {                                                            
4317             childrenLayouts.add(mLauncher.getHotseat().getLayout().getShortcutsAndWidgets());            
4318         }                                                                                                
4319         return childrenLayouts;                                                                          
4320     }                                                                                                    
4321                                                                                                          
4322     public Folder getFolderForTag(final Object tag) {                                                    
4323         return ((Folder) (getFirstMatch(new ItemOperator() {                                             
4324             @Override                                                                                    
4325             public boolean evaluate(ItemInfo info, View v, View parent) {                                
4326                 return ((v instanceof Folder) && (((Folder) (v)).getInfo() == tag)) && ((Folder) (v)).get🔵
4327             }                                                                                            
4328         })));                                                                                            
4329     }                                                                                                    
4330                                                                                                          
4331     public View getViewForTag(final Object tag) {                                                        
4332         return getFirstMatch(new ItemOperator() {                                                        
4333                                                                                                          
4334             @Override                                                                                    
4335             public boolean evaluate(ItemInfo info, View v, View parent) {                                
4336                 return info == tag;                                                                      
4337             }                                                                                            
4338         });                                                                                              
4339     }                                                                                                    
4340                                                                                                          
4341     public LauncherAppWidgetHostView getWidgetForAppWidgetId(final int appWidgetId) {                    
4342         return (LauncherAppWidgetHostView) getFirstMatch(new ItemOperator() {                            
4343                                                                                                          
4344             @Override                                                                                    
4345             public boolean evaluate(ItemInfo info, View v, View parent) {                                
4346                 return (info instanceof LauncherAppWidgetInfo) &&                                        
4347                         ((LauncherAppWidgetInfo) info).appWidgetId == appWidgetId;                       
4348             }                                                                                            
4349         });                                                                                              
4350     }                                                                                                    
4351                                                                                                          
4352     private View getFirstMatch(final ItemOperator operator) {                                            
4353         final View[] value = new View[1];                                                                
4354         mapOverItems(MAP_NO_RECURSE, new ItemOperator() {                                                
4355             @Override                                                                                    
4356             public boolean evaluate(ItemInfo info, View v, View parent) {                                
4357                 if (operator.evaluate(info, v, parent)) {                                                
4358                     value[0] = v;                                                                        
4359                     return true;                                                                         
4360                 }                                                                                        
4361                 return false;                                                                            
4362             }                                                                                            
4363         });                                                                                              
4364         return value[0];                                                                                 
4365     }                                                                                                    
4366                                                                                                          
4367     void clearDropTargets() {                                                                            
4368         mapOverItems(MAP_NO_RECURSE, new ItemOperator() {                                                
4369             @Override                                                                                    
4370             public boolean evaluate(ItemInfo info, View v, View parent) {                                
4371                 if (v instanceof DropTarget) {                                                           
4372                     mDragController.removeDropTarget(((DropTarget) (v)));                                
4373                 }                                                                                        
4374                 // not done, process all the shortcuts                                                   
4375                 return false;                                                                            
4376             }                                                                                            
4377         });                                                                                              
4378     }                                                                                                    
4379                                                                                                          
4380     // Removes ALL items that match a given package name, this is usually called when a package          
4381     // has been removed and we want to remove all components (widgets, shortcuts, apps) that             
4382     // belong to that package.                                                                           
4383     void removeItemsByPackageName(final ArrayList<String> packages, final UserHandleCompat user) {       
4384         final HashSet<String> packageNames = new HashSet<String>();                                      
4385         packageNames.addAll(packages);                                                                   
4386         // Filter out all the ItemInfos that this is going to affect                                     
4387         final HashSet<ItemInfo> infos = new HashSet<ItemInfo>();                                         
4388         final HashSet<ComponentName> cns = new HashSet<ComponentName>();                                 
4389         ArrayList<CellLayout> cellLayouts = getWorkspaceAndHotseatCellLayouts();                         
4390         for (CellLayout layoutParent : cellLayouts) {                                                    
4391             ViewGroup layout = layoutParent.getShortcutsAndWidgets();                                    
4392             int childCount = layout.getChildCount();                                                     
4393             for (int i = 0; i < childCount; ++i) {                                                       
4394                 View view = layout.getChildAt(i);                                                        
4395                 infos.add(((ItemInfo) (view.getTag())));                                                 
4396             }                                                                                            
4397         }                                                                                                
4398         LauncherModel.ItemInfoFilter filter = new LauncherModel.ItemInfoFilter() {                       
4399             @Override                                                                                    
4400             public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                
4401                 if (packageNames.contains(cn.getPackageName()) && info.user.equals(user)) {              
4402                     cns.add(cn);                                                                         
4403                     return true;                                                                         
4404                 }                                                                                        
4405                 return false;                                                                            
4406             }                                                                                            
4407         };                                                                                               
4408         LauncherModel.filterItemInfos(infos, filter);                                                    
4409         // Remove the affected components                                                                
4410         removeItemsByComponentName(cns, user);                                                           
4411     }                                                                                                    
4412                                                                                                          
4413     // Removes items that match the application info specified, when applications are removed            
4414     // as a part of an update, this is called to ensure that other widgets and application               
4415     // shortcuts are not removed.                                                                        
4416     void removeItemsByApplicationInfo(final ArrayList<AppInfo> appInfos, UserHandleCompat user) {        
4417         // Just create a hash table of all the specific components that this will affect                 
4418         HashSet<ComponentName> cns = new HashSet<ComponentName>();                                       
4419         for (AppInfo info : appInfos) {                                                                  
4420             cns.add(info.componentName);                                                                 
4421         }                                                                                                
4422         // Remove all the things                                                                         
4423         removeItemsByComponentName(cns, user);                                                           
4424     }                                                                                                    
4425                                                                                                          
4426     void removeItemsByComponentName(final HashSet<ComponentName> componentNames, final UserHandleCompat u🔵
4427         ArrayList<CellLayout> cellLayouts = getWorkspaceAndHotseatCellLayouts();                         
4428         for (final CellLayout layoutParent : cellLayouts) {                                              
4429             final ViewGroup layout = layoutParent.getShortcutsAndWidgets();                              
4430             final HashMap<ItemInfo, View> children = new HashMap<ItemInfo, View>();                      
4431             for (int j = 0; j < layout.getChildCount(); j++) {                                           
4432                 final View view = layout.getChildAt(j);                                                  
4433                 children.put(((ItemInfo) (view.getTag())), view);                                        
4434             }                                                                                            
4435             final ArrayList<View> childrenToRemove = new ArrayList<View>();                              
4436             final HashMap<FolderInfo, ArrayList<ShortcutInfo>> folderAppsToRemove = new HashMap<FolderInf🔵
4437             LauncherModel.ItemInfoFilter filter = new LauncherModel.ItemInfoFilter() {                   
4438                 @Override                                                                                
4439                 public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {            
4440                     if (parent instanceof FolderInfo) {                                                  
4441                         if (componentNames.contains(cn) && info.user.equals(user)) {                     
4442                             FolderInfo folder = ((FolderInfo) (parent));                                 
4443                             ArrayList<ShortcutInfo> appsToRemove;                                        
4444                             if (folderAppsToRemove.containsKey(folder)) {                                
4445                                 appsToRemove = folderAppsToRemove.get(folder);                           
4446                             } else {                                                                     
4447                                 appsToRemove = new ArrayList<ShortcutInfo>();                            
4448                                 folderAppsToRemove.put(folder, appsToRemove);                            
4449                             }                                                                            
4450                             appsToRemove.add(((ShortcutInfo) (info)));                                   
4451                             return true;                                                                 
4452                         }                                                                                
4453                     } else if (componentNames.contains(cn) && info.user.equals(user)) {                  
4454                         childrenToRemove.add(children.get(info));                                        
4455                         return true;                                                                     
4456                     }                                                                                    
4457                     return false;                                                                        
4458                 }                                                                                        
4459             };                                                                                           
4460             LauncherModel.filterItemInfos(children.keySet(), filter);                                    
4461             // Remove all the apps from their folders                                                    
4462             for (FolderInfo folder : folderAppsToRemove.keySet()) {                                      
4463                 ArrayList<ShortcutInfo> appsToRemove = folderAppsToRemove.get(folder);                   
4464                 for (ShortcutInfo info : appsToRemove) {                                                 
4465                     folder.remove(info);                                                                 
4466                 }                                                                                        
4467             }                                                                                            
4468             // Remove all the other children                                                             
4469             for (View child : childrenToRemove) {                                                        
4470                 // Note: We can not remove the view directly from CellLayoutChildren as this             
4471                 // does not re-mark the spaces as unoccupied.                                            
4472                 layoutParent.removeViewInLayout(child);                                                  
4473                 if (child instanceof DropTarget) {                                                       
4474                     mDragController.removeDropTarget(((DropTarget) (child)));                            
4475                 }                                                                                        
4476             }                                                                                            
4477             if (childrenToRemove.size() > 0) {                                                           
4478                 layout.requestLayout();                                                                  
4479                 layout.invalidate();                                                                     
4480             }                                                                                            
4481         }                                                                                                
4482         // Strip all the empty screens                                                                   
4483         stripEmptyScreens();                                                                             
4484     }                                                                                                    
4485                                                                                                          
4486     interface ItemOperator {                                                                             
4487         /**                                                                                              
4488          * Process the next itemInfo, possibly with side-effect on {@link ItemOperator#value}.           
4489          *                                                                                               
4490          * @param info                                                                                   
4491          * 		info for the shortcut                                                                       
4492          * @param view                                                                                   
4493          * 		view for the shortcut                                                                       
4494          * @param parent                                                                                 
4495          * 		containing folder, or null                                                                  
4496          * @return true if done, false to continue the map                                               
4497          */                                                                                              
4498         public abstract boolean evaluate(ItemInfo info, View view, View parent);                         
4499     }                                                                                                    
4500                                                                                                          
4501     /**                                                                                                  
4502      * Map the operator over the shortcuts and widgets, return the first-non-null value.                 
4503      *                                                                                                   
4504      * @param recurse true: iterate over folder children. false: op get the folders themselves.          
4505      * @param op the operator to map over the shortcuts                                                  
4506      */                                                                                                  
4507     void mapOverItems(boolean recurse, ItemOperator op) {                                                
4508         ArrayList<ShortcutAndWidgetContainer> containers = getAllShortcutAndWidgetContainers();          
4509         final int containerCount = containers.size();                                                    
4510         for (int containerIdx = 0; containerIdx < containerCount; containerIdx++) {                      
4511             ShortcutAndWidgetContainer container = containers.get(containerIdx);                         
4512             // map over all the shortcuts on the workspace                                               
4513             final int itemCount = container.getChildCount();                                             
4514             for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) {                                      
4515                 View item = container.getChildAt(itemIdx);                                               
4516                 ItemInfo info = ((ItemInfo) (item.getTag()));                                            
4517                 if ((recurse && (info instanceof FolderInfo)) && (item instanceof FolderIcon)) {         
4518                     FolderIcon folder = ((FolderIcon) (item));                                           
4519                     ArrayList<View> folderChildren = folder.getFolder().getItemsInReadingOrder();        
4520                     // map over all the children in the folder                                           
4521                     final int childCount = folderChildren.size();                                        
4522                     for (int childIdx = 0; childIdx < childCount; childIdx++) {                          
4523                         View child = folderChildren.get(childIdx);                                       
4524                         info = ((ItemInfo) (child.getTag()));                                            
4525                         if (op.evaluate(info, child, folder)) {                                          
4526                             return;                                                                      
4527                         }                                                                                
4528                     }                                                                                    
4529                 } else if (op.evaluate(info, item, null)) {                                              
4530                     return;                                                                              
4531                 }                                                                                        
4532             }                                                                                            
4533         }                                                                                                
4534     }                                                                                                    
4535                                                                                                          
4536     void updateShortcutsAndWidgets(ArrayList<AppInfo> apps) {                                            
4537         // Break the appinfo list per user                                                               
4538         final HashMap<UserHandleCompat, ArrayList<AppInfo>> appsPerUser = new HashMap<UserHandleCompat, A🔵
4539         for (AppInfo info : apps) {                                                                      
4540             ArrayList<AppInfo> filtered = appsPerUser.get(info.user);                                    
4541             if (filtered == null) {                                                                      
4542                 filtered = new ArrayList<AppInfo>();                                                     
4543                 appsPerUser.put(info.user, filtered);                                                    
4544             }                                                                                            
4545             filtered.add(info);                                                                          
4546         }                                                                                                
4547         for (Map.Entry<UserHandleCompat, ArrayList<AppInfo>> entry : appsPerUser.entrySet()) {           
4548             updateShortcutsAndWidgetsPerUser(entry.getValue(), entry.getKey());                          
4549         }                                                                                                
4550     }                                                                                                    
4551                                                                                                          
4552     private void updateShortcutsAndWidgetsPerUser(ArrayList<AppInfo> apps, final UserHandleCompat user) {
4553         // Create a map of the apps to test against                                                      
4554         final HashMap<ComponentName, AppInfo> appsMap = new HashMap<ComponentName, AppInfo>();           
4555         final HashSet<String> pkgNames = new HashSet<String>();                                          
4556         for (AppInfo ai : apps) {                                                                        
4557             appsMap.put(ai.componentName, ai);                                                           
4558             pkgNames.add(ai.componentName.getPackageName());                                             
4559         }                                                                                                
4560         final HashSet<ComponentName> iconsToRemove = new HashSet<ComponentName>();                       
4561         mapOverItems(MAP_RECURSE, new ItemOperator() {                                                   
4562             @Override                                                                                    
4563             public boolean evaluate(ItemInfo info, View v, View parent) {                                
4564                 if ((info instanceof ShortcutInfo) && (v instanceof BubbleTextView)) {                   
4565                     ShortcutInfo shortcutInfo = ((ShortcutInfo) (info));                                 
4566                     ComponentName cn = shortcutInfo.getTargetComponent();                                
4567                     AppInfo appInfo = appsMap.get(cn);                                                   
4568                     if (((user.equals(shortcutInfo.user) && (cn != null)) && LauncherModel.isShortcutInfo🔵
4569                         boolean promiseStateChanged = false;                                             
4570                         boolean infoUpdated = false;                                                     
4571                         if (shortcutInfo.isPromise()) {                                                  
4572                             if (shortcutInfo.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {         
4573                                 // Auto install icon                                                     
4574                                 PackageManager pm = getContext().getPackageManager();                    
4575                                 ResolveInfo matched = pm.resolveActivity(new Intent(Intent.ACTION_MAIN).s🔵
4576                                 if (matched == null) {                                                   
4577                                     // Try to find the best match activity.                              
4578                                     Intent intent = pm.getLaunchIntentForPackage(cn.getPackageName());   
4579                                     if (intent != null) {                                                
4580                                         cn = intent.getComponent();                                      
4581                                         appInfo = appsMap.get(cn);                                       
4582                                     }                                                                    
4583                                     if ((intent == null) || (appsMap == null)) {                         
4584                                         // Could not find a default activity. Remove this item.          
4585                                         iconsToRemove.add(shortcutInfo.getTargetComponent());            
4586                                         // process next shortcut.                                        
4587                                         return false;                                                    
4588                                     }                                                                    
4589                                     shortcutInfo.promisedIntent = intent;                                
4590                                 }                                                                        
4591                             }                                                                            
4592                             // Restore the shortcut.                                                     
4593                             shortcutInfo.intent = shortcutInfo.promisedIntent;                           
4594                             shortcutInfo.promisedIntent = null;                                          
4595                             shortcutInfo.status &= ((~ShortcutInfo.FLAG_RESTORED_ICON) & (~ShortcutInfo.F🔵
4596                             promiseStateChanged = true;                                                  
4597                             infoUpdated = true;                                                          
4598                             shortcutInfo.updateIcon(mIconCache);                                         
4599                             LauncherModel.updateItemInDatabase(getContext(), shortcutInfo);              
4600                         }                                                                                
4601                         if (appInfo != null) {                                                           
4602                             shortcutInfo.updateIcon(mIconCache);                                         
4603                             shortcutInfo.title = appInfo.title.toString();                               
4604                             shortcutInfo.contentDescription = appInfo.contentDescription;                
4605                             infoUpdated = true;                                                          
4606                         }                                                                                
4607                         if (infoUpdated) {                                                               
4608                             BubbleTextView shortcut = ((BubbleTextView) (v));                            
4609                             shortcut.applyFromShortcutInfo(shortcutInfo, mIconCache, true, promiseStateCh🔵
4610                             if (parent != null) {                                                        
4611                                 parent.invalidate();                                                     
4612                             }                                                                            
4613                         }                                                                                
4614                     }                                                                                    
4615                 }                                                                                        
4616                 // process all the shortcuts                                                             
4617                 return false;                                                                            
4618             }                                                                                            
4619         });                                                                                              
4620         if (!iconsToRemove.isEmpty()) {                                                                  
4621             removeItemsByComponentName(iconsToRemove, user);                                             
4622         }                                                                                                
4623         if (user.equals(UserHandleCompat.myUserHandle())) {                                              
4624             restorePendingWidgets(pkgNames);                                                             
4625         }                                                                                                
4626     }                                                                                                    
4627                                                                                                          
4628     public void removeAbandonedPromise(String packageName, UserHandleCompat user) {                      
4629         ArrayList<String> packages = new ArrayList<String>(1);                                           
4630         packages.add(packageName);                                                                       
4631         LauncherModel.deletePackageFromDatabase(mLauncher, packageName, user);                           
4632         removeItemsByPackageName(packages, user);                                                        
4633     }                                                                                                    
4634                                                                                                          
4635     public void updatePackageBadge(final String packageName, final UserHandleCompat user) {              
4636         mapOverItems(MAP_RECURSE, new ItemOperator() {                                                   
4637             @Override                                                                                    
4638             public boolean evaluate(ItemInfo info, View v, View parent) {                                
4639                 if ((info instanceof ShortcutInfo) && (v instanceof BubbleTextView)) {                   
4640                     ShortcutInfo shortcutInfo = ((ShortcutInfo) (info));                                 
4641                     ComponentName cn = shortcutInfo.getTargetComponent();                                
4642                     if (((user.equals(shortcutInfo.user) && (cn != null)) && shortcutInfo.isPromise()) &&🔵
4643                         if (shortcutInfo.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {             
4644                             // For auto install apps update the icon as well as label.                   
4645                             mIconCache.getTitleAndIcon(shortcutInfo, shortcutInfo.promisedIntent, user, t🔵
4646                         } else {                                                                         
4647                             // Only update the icon for restored apps.                                   
4648                             shortcutInfo.updateIcon(mIconCache);                                         
4649                         }                                                                                
4650                         BubbleTextView shortcut = ((BubbleTextView) (v));                                
4651                         shortcut.applyFromShortcutInfo(shortcutInfo, mIconCache, true, false);           
4652                         if (parent != null) {                                                            
4653                             parent.invalidate();                                                         
4654                         }                                                                                
4655                     }                                                                                    
4656                 }                                                                                        
4657                 // process all the shortcuts                                                             
4658                 return false;                                                                            
4659             }                                                                                            
4660         });                                                                                              
4661     }                                                                                                    
4662                                                                                                          
4663     public void updatePackageState(ArrayList<PackageInstallInfo> installInfos) {                         
4664         HashSet<String> completedPackages = new HashSet<String>();                                       
4665         for (final PackageInstallInfo installInfo : installInfos) {                                      
4666             mapOverItems(MAP_RECURSE, new ItemOperator() {                                               
4667                 @Override                                                                                
4668                 public boolean evaluate(ItemInfo info, View v, View parent) {                            
4669                     if ((info instanceof ShortcutInfo) && (v instanceof BubbleTextView)) {               
4670                         ShortcutInfo si = ((ShortcutInfo) (info));                                       
4671                         ComponentName cn = si.getTargetComponent();                                      
4672                         if ((si.isPromise() && (cn != null)) && installInfo.packageName.equals(cn.getPack🔵
4673                             si.setInstallProgress(installInfo.progress);                                 
4674                             if (installInfo.state == PackageInstallerCompat.STATUS_FAILED) {             
4675                                 // Mark this info as broken.                                             
4676                                 si.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;                  
4677                             }                                                                            
4678                             ((BubbleTextView) (v)).applyState(false);                                    
4679                         }                                                                                
4680                     } else if (((v instanceof PendingAppWidgetHostView) && (info instanceof LauncherAppWi🔵
4681                         ((LauncherAppWidgetInfo) (info)).installProgress = installInfo.progress;         
4682                         ((PendingAppWidgetHostView) (v)).applyState();                                   
4683                     }                                                                                    
4684                     // process all the shortcuts                                                         
4685                     return false;                                                                        
4686                 }                                                                                        
4687             });                                                                                          
4688             if (installInfo.state == PackageInstallerCompat.STATUS_INSTALLED) {                          
4689                 completedPackages.add(installInfo.packageName);                                          
4690             }                                                                                            
4691         }                                                                                                
4692         // Note that package states are sent only for myUser                                             
4693         if (!completedPackages.isEmpty()) {                                                              
4694             restorePendingWidgets(completedPackages);                                                    
4695         }                                                                                                
4696     }                                                                                                    
4697                                                                                                          
4698     private void restorePendingWidgets(final Set<String> installedPackaged) {                            
4699         final ArrayList<LauncherAppWidgetInfo> changedInfo = new ArrayList<LauncherAppWidgetInfo>();     
4700         // Iterate non recursively as widgets can't be inside a folder.                                  
4701         mapOverItems(MAP_NO_RECURSE, new ItemOperator() {                                                
4702             @Override                                                                                    
4703             public boolean evaluate(ItemInfo info, View v, View parent) {                                
4704                 if (info instanceof LauncherAppWidgetInfo) {                                             
4705                     LauncherAppWidgetInfo widgetInfo = ((LauncherAppWidgetInfo) (info));                 
4706                     if (widgetInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) && insta🔵
4707                         changedInfo.add(widgetInfo);                                                     
4708                         // Remove the provider not ready flag                                            
4709                         widgetInfo.restoreStatus &= ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;      
4710                         LauncherModel.updateItemInDatabase(getContext(), widgetInfo);                    
4711                     }                                                                                    
4712                 }                                                                                        
4713                 // process all the widget                                                                
4714                 return false;                                                                            
4715             }                                                                                            
4716         });                                                                                              
4717         if (!changedInfo.isEmpty()) {                                                                    
4718             DeferredWidgetRefresh widgetRefresh = new DeferredWidgetRefresh(changedInfo, mLauncher.getApp🔵
4719             if (LauncherModel.findAppWidgetProviderInfoWithComponent(getContext(), changedInfo.get(0).pro🔵
4720                 // Re-inflate the widgets which have changed status                                      
4721                 widgetRefresh.run();                                                                     
4722             } else {                                                                                     
4723                 // widgetRefresh will automatically run when the packages are updated.                   
4724             }                                                                                            
4725         }                                                                                                
4726     }                                                                                                    
4727                                                                                                          
4728     private void moveToScreen(int page, boolean animate) {                                               
4729         if (!workspaceInModalState()) {                                                                  
4730             if (animate) {                                                                               
4731                 snapToPage(page);                                                                        
4732             } else {                                                                                     
4733                 setCurrentPage(page);                                                                    
4734             }                                                                                            
4735         }                                                                                                
4736         View child = getChildAt(page);                                                                   
4737         if (child != null) {                                                                             
4738             child.requestFocus();                                                                        
4739         }                                                                                                
4740     }                                                                                                    
4741                                                                                                          
4742     void moveToDefaultScreen(boolean animate) {                                                          
4743         moveToScreen(mDefaultPage, animate);                                                             
4744     }                                                                                                    
4745                                                                                                          
4746     void moveToCustomContentScreen(boolean animate) {                                                    
4747         if (hasCustomContent()) {                                                                        
4748             int ccIndex = getPageIndexForScreenId(CUSTOM_CONTENT_SCREEN_ID);                             
4749             if (animate) {                                                                               
4750                 snapToPage(ccIndex);                                                                     
4751             } else {                                                                                     
4752                 setCurrentPage(ccIndex);                                                                 
4753             }                                                                                            
4754             View child = getChildAt(ccIndex);                                                            
4755             if (child != null) {                                                                         
4756                 child.requestFocus();                                                                    
4757             }                                                                                            
4758          }                                                                                               
4759         exitWidgetResizeMode();                                                                          
4760     }                                                                                                    
4761                                                                                                          
4762     @Override                                                                                            
4763     protected PageIndicator.PageMarkerResources getPageIndicatorMarker(int pageIndex) {                  
4764         long screenId = getScreenIdForPageIndex(pageIndex);                                              
4765         if (screenId == EXTRA_EMPTY_SCREEN_ID) {                                                         
4766             int count = mScreenOrder.size() - numCustomPages();                                          
4767             if (count > 1) {                                                                             
4768                 return new PageIndicator.PageMarkerResources(R.drawable.ic_pageindicator_current,        
4769                         R.drawable.ic_pageindicator_add);                                                
4770             }                                                                                            
4771         }                                                                                                
4772                                                                                                          
4773         return super.getPageIndicatorMarker(pageIndex);                                                  
4774     }                                                                                                    
4775                                                                                                          
4776     @Override                                                                                            
4777     public void syncPages() {                                                                            
4778     }                                                                                                    
4779                                                                                                          
4780     @Override                                                                                            
4781     public void syncPageItems(int page, boolean immediate) {                                             
4782     }                                                                                                    
4783                                                                                                          
4784     protected String getPageIndicatorDescription() {                                                     
4785         String settings = getResources().getString(R.string.settings_button_text);                       
4786         return getCurrentPageDescription() + ", " + settings;                                            
4787     }                                                                                                    
4788                                                                                                          
4789     protected String getCurrentPageDescription() {                                                       
4790         int page = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage;                               
4791         int delta = numCustomPages();                                                                    
4792         if (hasCustomContent() && getNextPage() == 0) {                                                  
4793             return mCustomContentDescription;                                                            
4794         }                                                                                                
4795         return String.format(getContext().getString(R.string.workspace_scroll_format),                   
4796                 page + 1 - delta, getChildCount() - delta);                                              
4797     }                                                                                                    
4798                                                                                                          
4799     public void getLocationInDragLayer(int[] loc) {                                                      
4800         mLauncher.getDragLayer().getLocationInDragLayer(this, loc);                                      
4801     }                                                                                                    
4802                                                                                                          
4803     /**                                                                                                  
4804      * Used as a workaround to ensure that the AppWidgetService receives the                             
4805      * PACKAGE_ADDED broadcast before updating widgets.                                                  
4806      */                                                                                                  
4807     private class DeferredWidgetRefresh implements Runnable {                                            
4808         private final ArrayList<LauncherAppWidgetInfo> mInfos;                                           
4809                                                                                                          
4810         private final LauncherAppWidgetHost mHost;                                                       
4811                                                                                                          
4812         private final Handler mHandler;                                                                  
4813                                                                                                          
4814         private boolean mRefreshPending;                                                                 
4815                                                                                                          
4816         public DeferredWidgetRefresh(ArrayList<LauncherAppWidgetInfo> infos, LauncherAppWidgetHost host) 🔵
4817             mInfos = infos;                                                                              
4818             mHost = host;                                                                                
4819             mHandler = new Handler();                                                                    
4820             mRefreshPending = true;                                                                      
4821             mHost.addProviderChangeListener(this);                                                       
4822             // Force refresh after 10 seconds, if we don't get the provider changed event.               
4823             // This could happen when the provider is no longer available in the app.                    
4824             mHandler.postDelayed(this, 10000);                                                           
4825         }                                                                                                
4826                                                                                                          
4827         @Override                                                                                        
4828         public void run() {                                                                              
4829             mHost.removeProviderChangeListener(this);                                                    
4830             mHandler.removeCallbacks(this);                                                              
4831                                                                                                          
4832             if (!mRefreshPending) {                                                                      
4833                 return;                                                                                  
4834             }                                                                                            
4835                                                                                                          
4836             mRefreshPending = false;                                                                     
4837                                                                                                          
4838             for (LauncherAppWidgetInfo info : mInfos) {                                                  
4839                 if (info.hostView instanceof PendingAppWidgetHostView) {                                 
4840                     PendingAppWidgetHostView view = (PendingAppWidgetHostView) info.hostView;            
4841                     mLauncher.removeAppWidget(info);                                                     
4842                                                                                                          
4843                     CellLayout cl = (CellLayout) view.getParent().getParent();                           
4844                     // Remove the current widget                                                         
4845                     cl.removeView(view);                                                                 
4846                     mLauncher.bindAppWidget(info);                                                       
4847                 }                                                                                        
4848             }                                                                                            
4849         }                                                                                                
4850     }                                                                                                    
4851 }                                                                                                        






























































































































































































































































































































































































































































ours vs. base theirs vs. base
   1  /*                                                                                                                
   2   * Copyright (C) 2008 The Android Open Source Project                                                             
   3   *                                                                                                                
   4   * Licensed under the Apache License, Version 2.0 (the "License");                                                
   5   * you may not use this file except in compliance with the License.                                               
   6   * You may obtain a copy of the License at                                                                        
   7   *                                                                                                                
   8   *      http://www.apache.org/licenses/LICENSE-2.0                                                                
   9   *                                                                                                                
  10   * Unless required by applicable law or agreed to in writing, software                                            
  11   * distributed under the License is distributed on an "AS IS" BASIS,                                              
  12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.                                       
  13   * See the License for the specific language governing permissions and                                            
  14   * limitations under the License.                                                                                 
  15   */                                                                                                               
  16                                                                                                                    
  17  package com.android.launcher3;                                                                                    
  18                                                                                                                    
  19  import android.animation.Animator;                                                                                
  20  import android.animation.Animator.AnimatorListener;                                                               
  21  import android.animation.AnimatorListenerAdapter;                                                                 
  22  import android.animation.AnimatorSet;                                                                             
  23  import android.animation.LayoutTransition;                                                                        
  24  import android.animation.ObjectAnimator;                                                                          
  25  import android.animation.PropertyValuesHolder;                                                                    
  26  import android.animation.TimeInterpolator;                                                                        
  27  import android.animation.ValueAnimator;                                                                           
  28  import android.animation.ValueAnimator.AnimatorUpdateListener;                                                    
  29  import android.app.WallpaperManager;                                                                              
  30  import android.appwidget.AppWidgetHostView;                                                                       
  31  import android.appwidget.AppWidgetProviderInfo;                                                                   
  32  import android.content.ComponentName;                                                                             
  33  import android.content.Context;                                                                                   
  34 +import android.content.Intent;                                                                                    
  35  import android.content.SharedPreferences;                                                                         
  36 +import android.content.pm.PackageManager;                                                                         
  37 +import android.content.pm.ResolveInfo;                                                                            
  38  import android.content.res.Resources;                                                                             
  39  import android.content.res.TypedArray;                                                                            
  40  import android.graphics.Bitmap;                                                                                   
  41  import android.graphics.Canvas;                                                                                   
  42  import android.graphics.Matrix;                                                                                   
  43 +import android.graphics.Paint;                                                                                    
  44  import android.graphics.Point;                                                                                    
  45  import android.graphics.PointF;                                                                                   
  46  import android.graphics.Rect;                                                                                     
  47  import android.graphics.Region.Op;                                                                                
  48  import android.graphics.drawable.Drawable;                                                                        
  49  import android.net.Uri;                                                                                           
  50  import android.os.AsyncTask;                                                                                      
  51 +import android.os.Handler;                                                                                        
  52  import android.os.IBinder;                                                                                        
  53  import android.os.Parcelable;                                                                                     
  54  import android.support.v4.view.ViewCompat;                                                                        
  55  import android.util.AttributeSet;                                                                                 
  56  import android.util.Log;                                                                                          
  57  import android.util.SparseArray;                                                                                  
  58  import android.view.Choreographer;                                                                                
  59  import android.view.Display;                                                                                      
  60  import android.view.MotionEvent;                                                                                  
  61  import android.view.View;                                                                                         
  62  import android.view.ViewGroup;                                                                                    
  63  import android.view.accessibility.AccessibilityManager;                                                           
  64  import android.view.animation.DecelerateInterpolator;                                                             
  65  import android.view.animation.Interpolator;                                                                       
  66  import android.widget.TextView;                                                                                   
  67                                                                                                                    
  68  import com.android.launcher3.FolderIcon.FolderRingAnimator;                                                       
  69  import com.android.launcher3.Launcher.CustomContentCallbacks;                                                     
  70  import com.android.launcher3.LauncherSettings.Favorites;                                                          
  71 +import com.android.launcher3.compat.PackageInstallerCompat;                                                       
  72 +import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;                                    
  73 +import com.android.launcher3.compat.UserHandleCompat;                                                             
  74                                                                                                                    
  75  import java.util.ArrayList;                                                                                       
  76  import java.util.HashMap;                                                                                         
  77  import java.util.HashSet;                                                                                         
  78  import java.util.Iterator;                                                                                        
  79 +import java.util.Map;                                                                                             
  80 +import java.util.Set;                                                                                             
  81 +import java.util.concurrent.atomic.AtomicInteger;                                                                 
  82                                                                                                                    
  83  /**                                                                                                               
  84   * The workspace is a wide area with a wallpaper and a finite number of pages.                                    
  85   * Each page contains a number of icons, folders or widgets the user can                                          
  86   * interact with. A workspace is meant to be used with a fixed width only.                                        
  87   */                                                                                                               
  88  public class Workspace extends SmoothPagedView                                                                    
  89          implements DropTarget, DragSource, DragScroller, View.OnTouchListener,                                    
  90          DragController.DragListener, LauncherTransitionable, ViewGroup.OnHierarchyChangeListener,                 
  91          Insettable {                                                                                              
  92      private static final String TAG = "Launcher.Workspace";                                                       
  93                                                                                                                    
  94      // Y rotation to apply to the workspace screens                                                               
  95      private static final float WORKSPACE_OVERSCROLL_ROTATION = 24f;                                               
  96                                                                                                                    
  97      private static final int CHILDREN_OUTLINE_FADE_OUT_DELAY = 0;                                                 
  98      private static final int CHILDREN_OUTLINE_FADE_OUT_DURATION = 375;                                            
  99      private static final int CHILDREN_OUTLINE_FADE_IN_DURATION = 100;                                             
 100                                                                                                                    
 101      protected static final int SNAP_OFF_EMPTY_SCREEN_DURATION = 400;                                              
 102      protected static final int FADE_EMPTY_SCREEN_DURATION = 150;                                                  
 103                                                                                                                    
 104      private static final int BACKGROUND_FADE_OUT_DURATION = 350;                                                  
 105      private static final int ADJACENT_SCREEN_DROP_DURATION = 300;                                                 
 106      private static final int FLING_THRESHOLD_VELOCITY = 500;                                                      
 107                                                                                                                    
 108      private static final float ALPHA_CUTOFF_THRESHOLD = 0.01f;                                                    
 109                                                                                                                    
 110 +    static final boolean MAP_NO_RECURSE = false;                                                                  
 111 +    static final boolean MAP_RECURSE = true;                                                                      
 112 +                                                                                                                  
 113      // These animators are used to fade the children's outlines                                                   
 114      private ObjectAnimator mChildrenOutlineFadeInAnimation;                                                       
 115      private ObjectAnimator mChildrenOutlineFadeOutAnimation;                                                      
 116      private float mChildrenOutlineAlpha = 0;                                                                      
 117                                                                                                                    
 118      // These properties refer to the background protection gradient used for AllApps and Customize                
 119      private ValueAnimator mBackgroundFadeInAnimation;                                                             
 120      private ValueAnimator mBackgroundFadeOutAnimation;                                                            
 121 -    private Drawable mBackground;                                                                                 
 122 -    boolean mDrawBackground = true;                                                                               
 123 -    private float mBackgroundAlpha = 0;                                                                           
 124                                                                                                                    
 125      private static final long CUSTOM_CONTENT_GESTURE_DELAY = 200;                                                 
 126      private long mTouchDownTime = -1;                                                                             
 127      private long mCustomContentShowTime = -1;                                                                     
 128                                                                                                                    
 129      private LayoutTransition mLayoutTransition;                                                                   
 130      private final WallpaperManager mWallpaperManager;                                                             
 131      private IBinder mWindowToken;                                                                                 
 132                                                                                                                    
 133      private int mOriginalDefaultPage;                                                                             
 134      private int mDefaultPage;                                                                                     
 135                                                                                                                    
 136      private ShortcutAndWidgetContainer mDragSourceInternal;                                                       
 137      private static boolean sAccessibilityEnabled;                                                                 
 138                                                                                                                    
 139      // The screen id used for the empty screen always present to the right.                                       
 140 -    private final static long EXTRA_EMPTY_SCREEN_ID = -201;                                                       
 141 +    final static long EXTRA_EMPTY_SCREEN_ID = -201;                                                               
 142      private final static long CUSTOM_CONTENT_SCREEN_ID = -301;                                                    
 143                                                                                                                    
 144      private HashMap<Long, CellLayout> mWorkspaceScreens = new HashMap<Long, CellLayout>();                        
 145      private ArrayList<Long> mScreenOrder = new ArrayList<Long>();                                                 
 146                                                                                                                    
 147      private Runnable mRemoveEmptyScreenRunnable;                                                                  
 148 +    private boolean mDeferRemoveExtraEmptyScreen = false;                                                         
 149                                                                                                                    
 150      /**                                                                                                           
 151       * CellInfo for the cell that is currently being dragged                                                      
 152       */                                                                                                           
 153      private CellLayout.CellInfo mDragInfo;                                                                        
 154                                                                                                                    
 155      /**                                                                                                           
 156       * Target drop area calculated during last acceptDrop call.                                                   
 157       */                                                                                                           
 158      private int[] mTargetCell = new int[2];                                                                       
 159      private int mDragOverX = -1;                                                                                  
 160      private int mDragOverY = -1;                                                                                  
 161                                                                                                                    
 162      static Rect mLandscapeCellLayoutMetrics = null;                                                               
 163      static Rect mPortraitCellLayoutMetrics = null;                                                                
 164                                                                                                                    
 165      CustomContentCallbacks mCustomContentCallbacks;                                                               
 166      boolean mCustomContentShowing;                                                                                
 167      private float mLastCustomContentScrollProgress = -1f;                                                         
 168      private String mCustomContentDescription = "";                                                                
 169                                                                                                                    
 170      /**                                                                                                           
 171       * The CellLayout that is currently being dragged over                                                        
 172       */                                                                                                           
 173      private CellLayout mDragTargetLayout = null;                                                                  
 174      /**                                                                                                           
 175       * The CellLayout that we will show as glowing                                                                
 176       */                                                                                                           
 177      private CellLayout mDragOverlappingLayout = null;                                                             
 178                                                                                                                    
 179      /**                                                                                                           
 180       * The CellLayout which will be dropped to                                                                    
 181       */                                                                                                           
 182      private CellLayout mDropToLayout = null;                                                                      
 183                                                                                                                    
 184      private Launcher mLauncher;                                                                                   
 185      private IconCache mIconCache;                                                                                 
 186      private DragController mDragController;                                                                       
 187                                                                                                                    
 188      // These are temporary variables to prevent having to allocate a new object just to                           
 189      // return an (x, y) value from helper functions. Do NOT use them to maintain other state.                     
 190      private int[] mTempCell = new int[2];                                                                         
 191      private int[] mTempPt = new int[2];                                                                           
 192      private int[] mTempEstimate = new int[2];                                                                     
 193      private float[] mDragViewVisualCenter = new float[2];                                                         
 194      private float[] mTempCellLayoutCenterCoordinates = new float[2];                                              
 195      private Matrix mTempInverseMatrix = new Matrix();                                                             
 196                                                                                                                    
 197      private SpringLoadedDragController mSpringLoadedDragController;                                               
 198      private float mSpringLoadedShrinkFactor;                                                                      
 199      private float mOverviewModeShrinkFactor;                                                                      
 200                                                                                                                    
 201      // State variable that indicates whether the pages are small (ie when you're                                  
 202      // in all apps or customize mode)                                                                             
 203                                                                                                                    
 204 -    enum State { NORMAL, SPRING_LOADED, SMALL, OVERVIEW};                                                         
 205 +    enum State { NORMAL, NORMAL_HIDDEN, SPRING_LOADED, OVERVIEW, OVERVIEW_HIDDEN};                                
 206      private State mState = State.NORMAL;                                                                          
 207      private boolean mIsSwitchingState = false;                                                                    
 208                                                                                                                    
 209      boolean mAnimatingViewIntoPlace = false;                                                                      
 210      boolean mIsDragOccuring = false;                                                                              
 211      boolean mChildrenLayersEnabled = true;                                                                        
 212                                                                                                                    
 213      private boolean mStripScreensOnPageStopMoving = false;                                                        
 214                                                                                                                    
 215      /** Is the user is dragging an item near the edge of a page? */                                               
 216      private boolean mInScrollArea = false;                                                                        
 217                                                                                                                    
 218      private HolographicOutlineHelper mOutlineHelper;                                                              
 219      private Bitmap mDragOutline = null;                                                                           
 220 -    private final Rect mTempRect = new Rect();                                                                    
 221 +    private static final Rect sTempRect = new Rect();                                                             
 222      private final int[] mTempXY = new int[2];                                                                     
 223      private int[] mTempVisiblePagesRange = new int[2];                                                            
 224 -    private boolean mOverscrollTransformsSet;                                                                     
 225 -    private float mLastOverscrollPivotX;                                                                          
 226 +    private boolean mOverscrollEffectSet;                                                                         
 227      public static final int DRAG_BITMAP_PADDING = 2;                                                              
 228      private boolean mWorkspaceFadeInAdjacentScreens;                                                              
 229                                                                                                                    
 230      WallpaperOffsetInterpolator mWallpaperOffset;                                                                 
 231      private boolean mWallpaperIsLiveWallpaper;                                                                    
 232      private int mNumPagesForWallpaperParallax;                                                                    
 233      private float mLastSetWallpaperOffsetSteps = 0;                                                               
 234                                                                                                                    
 235      private Runnable mDelayedResizeRunnable;                                                                      
 236      private Runnable mDelayedSnapToPageRunnable;                                                                  
 237      private Point mDisplaySize = new Point();                                                                     
 238      private int mCameraDistance;                                                                                  
 239                                                                                                                    
 240      // Variables relating to the creation of user folders by hovering shortcuts over shortcuts                    
 241      private static final int FOLDER_CREATION_TIMEOUT = 0;                                                         
 242      public static final int REORDER_TIMEOUT = 350;                                                                
 243      private final Alarm mFolderCreationAlarm = new Alarm();                                                       
 244      private final Alarm mReorderAlarm = new Alarm();                                                              
 245      private FolderRingAnimator mDragFolderRingAnimator = null;                                                    
 246      private FolderIcon mDragOverFolderIcon = null;                                                                
 247      private boolean mCreateUserFolderOnDrop = false;                                                              
 248      private boolean mAddToExistingFolderOnDrop = false;                                                           
 249      private DropTarget.DragEnforcer mDragEnforcer;                                                                
 250      private float mMaxDistanceForFolderCreation;                                                                  
 251                                                                                                                    
 252 +    private final Canvas mCanvas = new Canvas();                                                                  
 253 +                                                                                                                  
 254      // Variables relating to touch disambiguation (scrolling workspace vs. scrolling a widget)                    
 255      private float mXDown;                                                                                         
 256      private float mYDown;                                                                                         
 257      final static float START_DAMPING_TOUCH_SLOP_ANGLE = (float) Math.PI / 6;                                      
 258      final static float MAX_SWIPE_ANGLE = (float) Math.PI / 3;                                                     
 259      final static float TOUCH_SLOP_DAMPING_FACTOR = 4;                                                             
 260                                                                                                                    
 261      // Relating to the animation of items being dropped externally                                                
 262      public static final int ANIMATE_INTO_POSITION_AND_DISAPPEAR = 0;                                              
 263      public static final int ANIMATE_INTO_POSITION_AND_REMAIN = 1;                                                 
 264      public static final int ANIMATE_INTO_POSITION_AND_RESIZE = 2;                                                 
 265      public static final int COMPLETE_TWO_STAGE_WIDGET_DROP_ANIMATION = 3;                                         
 266      public static final int CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION = 4;                                           
 267                                                                                                                    
 268      // Related to dragging, folder creation and reordering                                                        
 269      private static final int DRAG_MODE_NONE = 0;                                                                  
 270      private static final int DRAG_MODE_CREATE_FOLDER = 1;                                                         
 271      private static final int DRAG_MODE_ADD_TO_FOLDER = 2;                                                         
 272      private static final int DRAG_MODE_REORDER = 3;                                                               
 273      private int mDragMode = DRAG_MODE_NONE;                                                                       
 274      private int mLastReorderX = -1;                                                                               
 275      private int mLastReorderY = -1;                                                                               
 276                                                                                                                    
 277      private SparseArray<Parcelable> mSavedStates;                                                                 
 278      private final ArrayList<Integer> mRestoredPages = new ArrayList<Integer>();                                   
 279                                                                                                                    
 280      // These variables are used for storing the initial and final values during workspace animations              
 281      private int mSavedScrollX;                                                                                    
 282      private float mSavedRotationY;                                                                                
 283      private float mSavedTranslationX;                                                                             
 284                                                                                                                    
 285      private float mCurrentScale;                                                                                  
 286      private float mNewScale;                                                                                      
 287      private float[] mOldBackgroundAlphas;                                                                         
 288      private float[] mOldAlphas;                                                                                   
 289      private float[] mNewBackgroundAlphas;                                                                         
 290      private float[] mNewAlphas;                                                                                   
 291      private int mLastChildCount = -1;                                                                             
 292      private float mTransitionProgress;                                                                            
 293 +                                                                                                                  
 294 +    float mOverScrollEffect = 0f;                                                                                 
 295                                                                                                                    
 296      private Runnable mDeferredAction;                                                                             
 297      private boolean mDeferDropAfterUninstall;                                                                     
 298      private boolean mUninstallSuccessful;                                                                         
 299                                                                                                                    
 300      private final Runnable mBindPages = new Runnable() {                                                          
 301          @Override                                                                                                 
 302          public void run() {                                                                                       
 303              mLauncher.getModel().bindRemainingSynchronousPages();                                                 
 304          }                                                                                                         
 305      };                                                                                                            
 306                                                                                                                    
 307      /**                                                                                                           
 308       * Used to inflate the Workspace from XML.                                                                    
 309       *                                                                                                            
 310       * @param context The application's context.                                                                  
 311       * @param attrs The attributes set containing the Workspace's customization values.                           
 312       */                                                                                                           
 313      public Workspace(Context context, AttributeSet attrs) {                                                       
 314          this(context, attrs, 0);                                                                                  
 315      }                                                                                                             
 316                                                                                                                    
 317      /**                                                                                                           
 318       * Used to inflate the Workspace from XML.                                                                    
 319       *                                                                                                            
 320       * @param context The application's context.                                                                  
 321       * @param attrs The attributes set containing the Workspace's customization values.                           
 322       * @param defStyle Unused.                                                                                    
 323       */                                                                                                           
 324      public Workspace(Context context, AttributeSet attrs, int defStyle) {                                         
 325          super(context, attrs, defStyle);                                                                          
 326          mContentIsRefreshable = false;                                                                            
 327                                                                                                                    
 328          mOutlineHelper = HolographicOutlineHelper.obtain(context);                                                
 329                                                                                                                    
 330          mDragEnforcer = new DropTarget.DragEnforcer(context);                                                     
 331          // With workspace, data is available straight from the get-go                                             
 332          setDataIsReady();                                                                                         
 333                                                                                                                    
 334          mLauncher = (Launcher) context;                                                                           
 335          final Resources res = getResources();                                                                     
 336          mWorkspaceFadeInAdjacentScreens = LauncherAppState.getInstance().getDynamicGrid().                        
 337                  getDeviceProfile().shouldFadeAdjacentWorkspaceScreens();                                          
 338          mFadeInAdjacentScreens = false;                                                                           
 339          mWallpaperManager = WallpaperManager.getInstance(context);                                                
 340                                                                                                                    
 341          LauncherAppState app = LauncherAppState.getInstance();                                                    
 342          DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                             
 343          TypedArray a = context.obtainStyledAttributes(attrs,                                                      
 344                  R.styleable.Workspace, defStyle, 0);                                                              
 345          mSpringLoadedShrinkFactor =                                                                               
 346              res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f;                        
 347          mOverviewModeShrinkFactor = grid.getOverviewModeScale();                                                  
 348          mCameraDistance = res.getInteger(R.integer.config_cameraDistance);                                        
 349          mOriginalDefaultPage = mDefaultPage = a.getInt(R.styleable.Workspace_defaultScreen, 1);                   
 350          a.recycle();                                                                                              
 351                                                                                                                    
 352          setOnHierarchyChangeListener(this);                                                                       
 353          setHapticFeedbackEnabled(false);                                                                          
 354                                                                                                                    
 355          initWorkspace();                                                                                          
 356                                                                                                                    
 357          // Disable multitouch across the workspace/all apps/customize tray                                        
 358          setMotionEventSplittingEnabled(true);                                                                     
 359          setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);                                       
 360      }                                                                                                             
 361                                                                                                                    
 362      @Override                                                                                                     
 363      public void setInsets(Rect insets) {                                                                          
 364          mInsets.set(insets);                                                                                      
 365                                                                                                                    
 366          CellLayout customScreen = getScreenWithId(CUSTOM_CONTENT_SCREEN_ID);                                      
 367          if (customScreen != null) {                                                                               
 368              View customContent = customScreen.getShortcutsAndWidgets().getChildAt(0);                             
 369              if (customContent instanceof Insettable) {                                                            
 370                  ((Insettable) customContent).setInsets(mInsets);                                                  
 371              }                                                                                                     
 372          }                                                                                                         
 373      }                                                                                                             
 374                                                                                                                    
 375      // estimate the size of a widget with spans hSpan, vSpan. return MAX_VALUE for each                           
 376      // dimension if unsuccessful                                                                                  
 377      public int[] estimateItemSize(int hSpan, int vSpan,                                                           
 378              ItemInfo itemInfo, boolean springLoaded) {                                                            
 379          int[] size = new int[2];                                                                                  
 380          if (getChildCount() > 0) {                                                                                
 381              // Use the first non-custom page to estimate the child position                                       
 382              CellLayout cl = (CellLayout) getChildAt(numCustomPages());                                            
 383              Rect r = estimateItemPosition(cl, itemInfo, 0, 0, hSpan, vSpan);                                      
 384              size[0] = r.width();                                                                                  
 385              size[1] = r.height();                                                                                 
 386              if (springLoaded) {                                                                                   
 387                  size[0] *= mSpringLoadedShrinkFactor;                                                             
 388                  size[1] *= mSpringLoadedShrinkFactor;                                                             
 389              }                                                                                                     
 390              return size;                                                                                          
 391          } else {                                                                                                  
 392              size[0] = Integer.MAX_VALUE;                                                                          
 393              size[1] = Integer.MAX_VALUE;                                                                          
 394              return size;                                                                                          
 395          }                                                                                                         
 396      }                                                                                                             
 397                                                                                                                    
 398      public Rect estimateItemPosition(CellLayout cl, ItemInfo pendingInfo,                                         
 399              int hCell, int vCell, int hSpan, int vSpan) {                                                         
 400          Rect r = new Rect();                                                                                      
 401          cl.cellToRect(hCell, vCell, hSpan, vSpan, r);                                                             
 402          return r;                                                                                                 
 403      }                                                                                                             
 404                                                                                                                    
 405      public void onDragStart(final DragSource source, Object info, int dragAction) {                               
 406          mIsDragOccuring = true;                                                                                   
 407          updateChildrenLayersEnabled(false);                                                                       
 408          mLauncher.lockScreenOrientation();                                                                        
 409          mLauncher.onInteractionBegin();                                                                           
 410          setChildrenBackgroundAlphaMultipliers(1f);                                                                
 411          // Prevent any Un/InstallShortcutReceivers from updating the db while we are dragging                     
 412          InstallShortcutReceiver.enableInstallQueue();                                                             
 413          UninstallShortcutReceiver.enableUninstallQueue();                                                         
 414          post(new Runnable() {                                                                                     
 415              @Override                                                                                             
 416              public void run() {                                                                                   
 417                  if (mIsDragOccuring) {                                                                            
 418 +                    mDeferRemoveExtraEmptyScreen = false;                                                         
 419                      addExtraEmptyScreenOnDrag();                                                                  
 420                  }                                                                                                 
 421              }                                                                                                     
 422          });                                                                                                       
 423      }                                                                                                             
 424                                                                                                                    
 425 +                                                                                                                  
 426 +    public void deferRemoveExtraEmptyScreen() {                                                                   
 427 +        mDeferRemoveExtraEmptyScreen = true;                                                                      
 428 +    }                                                                                                             
 429 +                                                                                                                  
 430      public void onDragEnd() {                                                                                     
 431 +        if (!mDeferRemoveExtraEmptyScreen) {                                                                      
 432 +            removeExtraEmptyScreen(true, mDragSourceInternal != null);                                            
 433 +        }                                                                                                         
 434 +                                                                                                                  
 435          mIsDragOccuring = false;                                                                                  
 436          updateChildrenLayersEnabled(false);                                                                       
 437          mLauncher.unlockScreenOrientation(false);                                                                 
 438                                                                                                                    
 439          // Re-enable any Un/InstallShortcutReceiver and now process any queued items                              
 440          InstallShortcutReceiver.disableAndFlushInstallQueue(getContext());                                        
 441          UninstallShortcutReceiver.disableAndFlushUninstallQueue(getContext());                                    
 442                                                                                                                    
 443          mDragSourceInternal = null;                                                                               
 444          mLauncher.onInteractionEnd();                                                                             
 445      }                                                                                                             
 446                                                                                                                    
 447      /**                                                                                                           
 448       * Initializes various states for this workspace.                                                             
 449       */                                                                                                           
 450      protected void initWorkspace() {                                                                              
 451 -        Context context = getContext();                                                                           
 452          mCurrentPage = mDefaultPage;                                                                              
 453          Launcher.setScreen(mCurrentPage);                                                                         
 454          LauncherAppState app = LauncherAppState.getInstance();                                                    
 455          DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                             
 456          mIconCache = app.getIconCache();                                                                          
 457          setWillNotDraw(false);                                                                                    
 458          setClipChildren(false);                                                                                   
 459          setClipToPadding(false);                                                                                  
 460          setChildrenDrawnWithCacheEnabled(true);                                                                   
 461                                                                                                                    
 462          setMinScale(mOverviewModeShrinkFactor);                                                                   
 463          setupLayoutTransition();                                                                                  
 464 -                                                                                                                  
 465 -        final Resources res = getResources();                                                                     
 466 -        try {                                                                                                     
 467 -            mBackground = res.getDrawable(R.drawable.apps_customize_bg);                                          
 468 -        } catch (Resources.NotFoundException e) {                                                                 
 469 -            // In this case, we will skip drawing background protection                                           
 470 -        }                                                                                                         
 471                                                                                                                    
 472          mWallpaperOffset = new WallpaperOffsetInterpolator();                                                     
 473          Display display = mLauncher.getWindowManager().getDefaultDisplay();                                       
 474          display.getSize(mDisplaySize);                                                                            
 475                                                                                                                    
 476          mMaxDistanceForFolderCreation = (0.55f * grid.iconSizePx);                                                
 477          mFlingThresholdVelocity = (int) (FLING_THRESHOLD_VELOCITY * mDensity);                                    
 478                                                                                                                    
 479          // Set the wallpaper dimensions when Launcher starts up                                                   
 480          setWallpaperDimension();                                                                                  
 481      }                                                                                                             
 482                                                                                                                    
 483      private void setupLayoutTransition() {                                                                        
 484          // We want to show layout transitions when pages are deleted, to close the gap.                           
 485          mLayoutTransition = new LayoutTransition();                                                               
 486          mLayoutTransition.enableTransitionType(LayoutTransition.DISAPPEARING);                                    
 487          mLayoutTransition.enableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);                             
 488          mLayoutTransition.disableTransitionType(LayoutTransition.APPEARING);                                      
 489          mLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_APPEARING);                               
 490          setLayoutTransition(mLayoutTransition);                                                                   
 491      }                                                                                                             
 492                                                                                                                    
 493      void enableLayoutTransitions() {                                                                              
 494          setLayoutTransition(mLayoutTransition);                                                                   
 495      }                                                                                                             
 496      void disableLayoutTransitions() {                                                                             
 497          setLayoutTransition(null);                                                                                
 498      }                                                                                                             
 499                                                                                                                    
 500      @Override                                                                                                     
 501      protected int getScrollMode() {                                                                               
 502          return SmoothPagedView.X_LARGE_MODE;                                                                      
 503      }                                                                                                             
 504                                                                                                                    
 505      @Override                                                                                                     
 506      public void onChildViewAdded(View parent, View child) {                                                       
 507          if (!(child instanceof CellLayout)) {                                                                     
 508              throw new IllegalArgumentException("A Workspace can only have CellLayout children.");                 
 509          }                                                                                                         
 510          CellLayout cl = ((CellLayout) child);                                                                     
 511          cl.setOnInterceptTouchListener(this);                                                                     
 512          cl.setClickable(true);                                                                                    
 513          cl.setImportantForAccessibility(ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO);                               
 514          super.onChildViewAdded(parent, child);                                                                    
 515      }                                                                                                             
 516                                                                                                                    
 517      protected boolean shouldDrawChild(View child) {                                                               
 518          final CellLayout cl = (CellLayout) child;                                                                 
 519          return super.shouldDrawChild(child) &&                                                                    
 520              (mIsSwitchingState ||                                                                                 
 521               cl.getShortcutsAndWidgets().getAlpha() > 0 ||                                                        
 522               cl.getBackgroundAlpha() > 0);                                                                        
 523      }                                                                                                             
 524                                                                                                                    
 525      /**                                                                                                           
 526       * @return The open folder on the current screen, or null if there is none                                    
 527       */                                                                                                           
 528      Folder getOpenFolder() {                                                                                      
 529          DragLayer dragLayer = mLauncher.getDragLayer();                                                           
 530          int count = dragLayer.getChildCount();                                                                    
 531          for (int i = 0; i < count; i++) {                                                                         
 532              View child = dragLayer.getChildAt(i);                                                                 
 533              if (child instanceof Folder) {                                                                        
 534                  Folder folder = (Folder) child;                                                                   
 535                  if (folder.getInfo().opened)                                                                      
 536                      return folder;                                                                                
 537              }                                                                                                     
 538          }                                                                                                         
 539          return null;                                                                                              
 540      }                                                                                                             
 541                                                                                                                    
 542      boolean isTouchActive() {                                                                                     
 543          return mTouchState != TOUCH_STATE_REST;                                                                   
 544      }                                                                                                             
 545                                                                                                                    
 546      public void removeAllWorkspaceScreens() {                                                                     
 547          // Disable all layout transitions before removing all pages to ensure that we don't get the               
 548          // transition animations competing with us changing the scroll when we add pages or the                   
 549          // custom content screen                                                                                  
 550          disableLayoutTransitions();                                                                               
 551                                                                                                                    
 552          // Since we increment the current page when we call addCustomContentPage via bindScreens                  
 553          // (and other places), we need to adjust the current page back when we clear the pages                    
 554          if (hasCustomContent()) {                                                                                 
 555              removeCustomContentPage();                                                                            
 556          }                                                                                                         
 557                                                                                                                    
 558          // Remove the pages and clear the screen models                                                           
 559          removeAllViews();                                                                                         
 560          mScreenOrder.clear();                                                                                     
 561          mWorkspaceScreens.clear();                                                                                
 562                                                                                                                    
 563          // Re-enable the layout transitions                                                                       
 564          enableLayoutTransitions();                                                                                
 565      }                                                                                                             
 566                                                                                                                    
 567      public long insertNewWorkspaceScreenBeforeEmptyScreen(long screenId) {                                        
 568          // Find the index to insert this view into.  If the empty screen exists, then                             
 569          // insert it before that.                                                                                 
 570          int insertIndex = mScreenOrder.indexOf(EXTRA_EMPTY_SCREEN_ID);                                            
 571          if (insertIndex < 0) {                                                                                    
 572              insertIndex = mScreenOrder.size();                                                                    
 573          }                                                                                                         
 574          return insertNewWorkspaceScreen(screenId, insertIndex);                                                   
 575      }                                                                                                             
 576                                                                                                                    
 577      public long insertNewWorkspaceScreen(long screenId) {                                                         
 578          return insertNewWorkspaceScreen(screenId, getChildCount());                                               
 579      }                                                                                                             
 580                                                                                                                    
 581      public long insertNewWorkspaceScreen(long screenId, int insertIndex) {                                        
 582          // Log to disk                                                                                            
 583          Launcher.addDumpLog(TAG, "11683562 - insertNewWorkspaceScreen(): " + screenId +                           
 584                  " at index: " + insertIndex, true);                                                               
 585                                                                                                                    
 586          if (mWorkspaceScreens.containsKey(screenId)) {                                                            
 587              throw new RuntimeException("Screen id " + screenId + " already exists!");                             
 588          }                                                                                                         
 589                                                                                                                    
 590          CellLayout newScreen = (CellLayout)                                                                       
 591                  mLauncher.getLayoutInflater().inflate(R.layout.workspace_screen, null);                           
 592                                                                                                                    
 593          newScreen.setOnLongClickListener(mLongClickListener);                                                     
 594          newScreen.setOnClickListener(mLauncher);                                                                  
 595          newScreen.setSoundEffectsEnabled(false);                                                                  
 596          mWorkspaceScreens.put(screenId, newScreen);                                                               
 597          mScreenOrder.add(insertIndex, screenId);                                                                  
 598          addView(newScreen, insertIndex);                                                                          
 599          return screenId;                                                                                          
 600      }                                                                                                             
 601                                                                                                                    
 602      public void createCustomContentContainer() {                                                                  
 603          CellLayout customScreen = (CellLayout)                                                                    
 604                  mLauncher.getLayoutInflater().inflate(R.layout.workspace_screen, null);                           
 605          customScreen.disableBackground();                                                                         
 606 +        customScreen.disableDragTarget();                                                                         
 607                                                                                                                    
 608          mWorkspaceScreens.put(CUSTOM_CONTENT_SCREEN_ID, customScreen);                                            
 609          mScreenOrder.add(0, CUSTOM_CONTENT_SCREEN_ID);                                                            
 610                                                                                                                    
 611          // We want no padding on the custom content                                                               
 612          customScreen.setPadding(0, 0, 0, 0);                                                                      
 613                                                                                                                    
 614          addFullScreenPage(customScreen);                                                                          
 615                                                                                                                    
 616          // Ensure that the current page and default page are maintained.                                          
 617          mDefaultPage = mOriginalDefaultPage + 1;                                                                  
 618                                                                                                                    
 619          // Update the custom content hint                                                                         
 620 -        mLauncher.getLauncherClings().updateCustomContentHintVisibility();                                        
 621          if (mRestorePage != INVALID_RESTORE_PAGE) {                                                               
 622              mRestorePage = mRestorePage + 1;                                                                      
 623          } else {                                                                                                  
 624              setCurrentPage(getCurrentPage() + 1);                                                                 
 625          }                                                                                                         
 626      }                                                                                                             
 627                                                                                                                    
 628      public void removeCustomContentPage() {                                                                       
 629          CellLayout customScreen = getScreenWithId(CUSTOM_CONTENT_SCREEN_ID);                                      
 630          if (customScreen == null) {                                                                               
 631              throw new RuntimeException("Expected custom content screen to exist");                                
 632          }                                                                                                         
 633                                                                                                                    
 634          mWorkspaceScreens.remove(CUSTOM_CONTENT_SCREEN_ID);                                                       
 635          mScreenOrder.remove(CUSTOM_CONTENT_SCREEN_ID);                                                            
 636          removeView(customScreen);                                                                                 
 637                                                                                                                    
 638          if (mCustomContentCallbacks != null) {                                                                    
 639              mCustomContentCallbacks.onScrollProgressChanged(0);                                                   
 640              mCustomContentCallbacks.onHide();                                                                     
 641          }                                                                                                         
 642                                                                                                                    
 643          mCustomContentCallbacks = null;                                                                           
 644                                                                                                                    
 645          // Ensure that the current page and default page are maintained.                                          
 646          mDefaultPage = mOriginalDefaultPage - 1;                                                                  
 647                                                                                                                    
 648          // Update the custom content hint                                                                         
 649 -        mLauncher.getLauncherClings().updateCustomContentHintVisibility();                                        
 650          if (mRestorePage != INVALID_RESTORE_PAGE) {                                                               
 651              mRestorePage = mRestorePage - 1;                                                                      
 652          } else {                                                                                                  
 653              setCurrentPage(getCurrentPage() - 1);                                                                 
 654          }                                                                                                         
 655      }                                                                                                             
 656                                                                                                                    
 657      public void addToCustomContentPage(View customContent, CustomContentCallbacks callbacks,                      
 658              String description) {                                                                                 
 659          if (getPageIndexForScreenId(CUSTOM_CONTENT_SCREEN_ID) < 0) {                                              
 660              throw new RuntimeException("Expected custom content screen to exist");                                
 661          }                                                                                                         
 662                                                                                                                    
 663          // Add the custom content to the full screen custom page                                                  
 664          CellLayout customScreen = getScreenWithId(CUSTOM_CONTENT_SCREEN_ID);                                      
 665          int spanX = customScreen.getCountX();                                                                     
 666          int spanY = customScreen.getCountY();                                                                     
 667          CellLayout.LayoutParams lp = new CellLayout.LayoutParams(0, 0, spanX, spanY);                             
 668          lp.canReorder  = false;                                                                                   
 669          lp.isFullscreen = true;                                                                                   
 670          if (customContent instanceof Insettable) {                                                                
 671              ((Insettable)customContent).setInsets(mInsets);                                                       
 672          }                                                                                                         
 673                                                                                                                    
 674          // Verify that the child is removed from any existing parent.                                             
 675          if (customContent.getParent() instanceof ViewGroup) {                                                     
 676              ViewGroup parent = (ViewGroup) customContent.getParent();                                             
 677              parent.removeView(customContent);                                                                     
 678          }                                                                                                         
 679          customScreen.removeAllViews();                                                                            
 680          customScreen.addViewToCellLayout(customContent, 0, 0, lp, true);                                          
 681          mCustomContentDescription = description;                                                                  
 682                                                                                                                    
 683          mCustomContentCallbacks = callbacks;                                                                      
 684      }                                                                                                             
 685                                                                                                                    
 686      public void addExtraEmptyScreenOnDrag() {                                                                     
 687          // Log to disk                                                                                            
 688          Launcher.addDumpLog(TAG, "11683562 - addExtraEmptyScreenOnDrag()", true);                                 
 689                                                                                                                    
 690          boolean lastChildOnScreen = false;                                                                        
 691          boolean childOnFinalScreen = false;                                                                       
 692                                                                                                                    
 693          // Cancel any pending removal of empty screen                                                             
 694          mRemoveEmptyScreenRunnable = null;                                                                        
 695                                                                                                                    
 696          if (mDragSourceInternal != null) {                                                                        
 697              if (mDragSourceInternal.getChildCount() == 1) {                                                       
 698                  lastChildOnScreen = true;                                                                         
 699              }                                                                                                     
 700              CellLayout cl = (CellLayout) mDragSourceInternal.getParent();                                         
 701              if (indexOfChild(cl) == getChildCount() - 1) {                                                        
 702                  childOnFinalScreen = true;                                                                        
 703              }                                                                                                     
 704          }                                                                                                         
 705                                                                                                                    
 706          // If this is the last item on the final screen                                                           
 707          if (lastChildOnScreen && childOnFinalScreen) {                                                            
 708              return;                                                                                               
 709          }                                                                                                         
 710          if (!mWorkspaceScreens.containsKey(EXTRA_EMPTY_SCREEN_ID)) {                                              
 711              insertNewWorkspaceScreen(EXTRA_EMPTY_SCREEN_ID);                                                      
 712          }                                                                                                         
 713      }                                                                                                             
 714                                                                                                                    
 715      public boolean addExtraEmptyScreen() {                                                                        
 716          // Log to disk                                                                                            
 717          Launcher.addDumpLog(TAG, "11683562 - addExtraEmptyScreen()", true);                                       
 718                                                                                                                    
 719          if (!mWorkspaceScreens.containsKey(EXTRA_EMPTY_SCREEN_ID)) {                                              
 720              insertNewWorkspaceScreen(EXTRA_EMPTY_SCREEN_ID);                                                      
 721              return true;                                                                                          
 722          }                                                                                                         
 723          return false;                                                                                             
 724      }                                                                                                             
 725                                                                                                                    
 726      private void convertFinalScreenToEmptyScreenIfNecessary() {                                                   
 727          // Log to disk                                                                                            
 728          Launcher.addDumpLog(TAG, "11683562 - convertFinalScreenToEmptyScreenIfNecessary()", true);                
 729                                                                                                                    
 730 +        if (mLauncher.isWorkspaceLoading()) {                                                                     
 731 +            // Invalid and dangerous operation if workspace is loading                                            
 732 +            Launcher.addDumpLog(TAG, "    - workspace loading, skip", true);                                      
 733 +            return;                                                                                               
 734 +        }                                                                                                         
 735 +                                                                                                                  
 736          if (hasExtraEmptyScreen() || mScreenOrder.size() == 0) return;                                            
 737          long finalScreenId = mScreenOrder.get(mScreenOrder.size() - 1);                                           
 738                                                                                                                    
 739          if (finalScreenId == CUSTOM_CONTENT_SCREEN_ID) return;                                                    
 740          CellLayout finalScreen = mWorkspaceScreens.get(finalScreenId);                                            
 741                                                                                                                    
 742          // If the final screen is empty, convert it to the extra empty screen                                     
 743          if (finalScreen.getShortcutsAndWidgets().getChildCount() == 0 &&                                          
 744                  !finalScreen.isDropPending()) {                                                                   
 745              mWorkspaceScreens.remove(finalScreenId);                                                              
 746              mScreenOrder.remove(finalScreenId);                                                                   
 747                                                                                                                    
 748              // if this is the last non-custom content screen, convert it to the empty screen                      
 749              mWorkspaceScreens.put(EXTRA_EMPTY_SCREEN_ID, finalScreen);                                            
 750              mScreenOrder.add(EXTRA_EMPTY_SCREEN_ID);                                                              
 751                                                                                                                    
 752              // Update the model if we have changed any screens                                                    
 753              mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder);                             
 754              Launcher.addDumpLog(TAG, "11683562 -   extra empty screen: " + finalScreenId, true);                  
 755          }                                                                                                         
 756      }                                                                                                             
 757                                                                                                                    
 758 -    public void removeExtraEmptyScreen(final boolean animate, final Runnable onComplete) {                        
 759 -        removeExtraEmptyScreen(animate, onComplete, 0, false);                                                    
 760 -    }                                                                                                             
 761 -                                                                                                                  
 762 -    public void removeExtraEmptyScreen(final boolean animate, final Runnable onComplete,                          
 763 +    public void removeExtraEmptyScreen(final boolean animate, boolean stripEmptyScreens) {                        
 764 +        removeExtraEmptyScreenDelayed(animate, null, 0, stripEmptyScreens);                                       
 765 +    }                                                                                                             
 766 +                                                                                                                  
 767 +    public void removeExtraEmptyScreenDelayed(final boolean animate, final Runnable onComplete,                   
 768              final int delay, final boolean stripEmptyScreens) {                                                   
 769          // Log to disk                                                                                            
 770          Launcher.addDumpLog(TAG, "11683562 - removeExtraEmptyScreen()", true);                                    
 771 +        if (mLauncher.isWorkspaceLoading()) {                                                                     
 772 +            // Don't strip empty screens if the workspace is still loading                                        
 773 +            Launcher.addDumpLog(TAG, "    - workspace loading, skip", true);                                      
 774 +            return;                                                                                               
 775 +        }                                                                                                         
 776 +                                                                                                                  
 777          if (delay > 0) {                                                                                          
 778              postDelayed(new Runnable() {                                                                          
 779                  @Override                                                                                         
 780                  public void run() {                                                                               
 781 -                    removeExtraEmptyScreen(animate, onComplete, 0, stripEmptyScreens);                            
 782 -                }                                                                                                 
 783 -                                                                                                                  
 784 +                    removeExtraEmptyScreenDelayed(animate, onComplete, 0, stripEmptyScreens);                     
 785 +                }                                                                                                 
 786              }, delay);                                                                                            
 787              return;                                                                                               
 788          }                                                                                                         
 789                                                                                                                    
 790          convertFinalScreenToEmptyScreenIfNecessary();                                                             
 791          if (hasExtraEmptyScreen()) {                                                                              
 792              int emptyIndex = mScreenOrder.indexOf(EXTRA_EMPTY_SCREEN_ID);                                         
 793              if (getNextPage() == emptyIndex) {                                                                    
 794                  snapToPage(getNextPage() - 1, SNAP_OFF_EMPTY_SCREEN_DURATION);                                    
 795                  fadeAndRemoveEmptyScreen(SNAP_OFF_EMPTY_SCREEN_DURATION, FADE_EMPTY_SCREEN_DURATION,              
 796                          onComplete, stripEmptyScreens);                                                           
 797              } else {                                                                                              
 798                  fadeAndRemoveEmptyScreen(0, FADE_EMPTY_SCREEN_DURATION,                                           
 799                          onComplete, stripEmptyScreens);                                                           
 800              }                                                                                                     
 801              return;                                                                                               
 802          } else if (stripEmptyScreens) {                                                                           
 803              // If we're not going to strip the empty screens after removing                                       
 804              // the extra empty screen, do it right away.                                                          
 805              stripEmptyScreens();                                                                                  
 806          }                                                                                                         
 807                                                                                                                    
 808          if (onComplete != null) {                                                                                 
 809              onComplete.run();                                                                                     
 810          }                                                                                                         
 811      }                                                                                                             
 812                                                                                                                    
 813      private void fadeAndRemoveEmptyScreen(int delay, int duration, final Runnable onComplete,                     
 814              final boolean stripEmptyScreens) {                                                                    
 815          // Log to disk                                                                                            
 816          // XXX: Do we need to update LM workspace screens below?                                                  
 817          Launcher.addDumpLog(TAG, "11683562 - fadeAndRemoveEmptyScreen()", true);                                  
 818          PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat("alpha", 0f);                                   
 819          PropertyValuesHolder bgAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha", 0f);                       
 820                                                                                                                    
 821          final CellLayout cl = mWorkspaceScreens.get(EXTRA_EMPTY_SCREEN_ID);                                       
 822                                                                                                                    
 823          mRemoveEmptyScreenRunnable = new Runnable() {                                                             
 824              @Override                                                                                             
 825              public void run() {                                                                                   
 826                  if (hasExtraEmptyScreen()) {                                                                      
 827                      mWorkspaceScreens.remove(EXTRA_EMPTY_SCREEN_ID);                                              
 828                      mScreenOrder.remove(EXTRA_EMPTY_SCREEN_ID);                                                   
 829                      removeView(cl);                                                                               
 830                      if (stripEmptyScreens) {                                                                      
 831                          stripEmptyScreens();                                                                      
 832                      }                                                                                             
 833                  }                                                                                                 
 834              }                                                                                                     
 835          };                                                                                                        
 836                                                                                                                    
 837          ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(cl, alpha, bgAlpha);                            
 838          oa.setDuration(duration);                                                                                 
 839          oa.setStartDelay(delay);                                                                                  
 840          oa.addListener(new AnimatorListenerAdapter() {                                                            
 841              @Override                                                                                             
 842              public void onAnimationEnd(Animator animation) {                                                      
 843                  if (mRemoveEmptyScreenRunnable != null) {                                                         
 844                      mRemoveEmptyScreenRunnable.run();                                                             
 845                  }                                                                                                 
 846                  if (onComplete != null) {                                                                         
 847                      onComplete.run();                                                                             
 848                  }                                                                                                 
 849              }                                                                                                     
 850          });                                                                                                       
 851          oa.start();                                                                                               
 852      }                                                                                                             
 853                                                                                                                    
 854      public boolean hasExtraEmptyScreen() {                                                                        
 855          int nScreens = getChildCount();                                                                           
 856          nScreens = nScreens - numCustomPages();                                                                   
 857          return mWorkspaceScreens.containsKey(EXTRA_EMPTY_SCREEN_ID) && nScreens > 1;                              
 858      }                                                                                                             
 859                                                                                                                    
 860      public long commitExtraEmptyScreen() {                                                                        
 861          // Log to disk                                                                                            
 862          Launcher.addDumpLog(TAG, "11683562 - commitExtraEmptyScreen()", true);                                    
 863 +        if (mLauncher.isWorkspaceLoading()) {                                                                     
 864 +            // Invalid and dangerous operation if workspace is loading                                            
 865 +            Launcher.addDumpLog(TAG, "    - workspace loading, skip", true);                                      
 866 +            return -1;                                                                                            
 867 +        }                                                                                                         
 868                                                                                                                    
 869          int index = getPageIndexForScreenId(EXTRA_EMPTY_SCREEN_ID);                                               
 870          CellLayout cl = mWorkspaceScreens.get(EXTRA_EMPTY_SCREEN_ID);                                             
 871          mWorkspaceScreens.remove(EXTRA_EMPTY_SCREEN_ID);                                                          
 872          mScreenOrder.remove(EXTRA_EMPTY_SCREEN_ID);                                                               
 873                                                                                                                    
 874          long newId = LauncherAppState.getLauncherProvider().generateNewScreenId();                                
 875          mWorkspaceScreens.put(newId, cl);                                                                         
 876          mScreenOrder.add(newId);                                                                                  
 877                                                                                                                    
 878          // Update the page indicator marker                                                                       
 879          if (getPageIndicator() != null) {                                                                         
 880              getPageIndicator().updateMarker(index, getPageIndicatorMarker(index));                                
 881          }                                                                                                         
 882                                                                                                                    
 883          // Update the model for the new screen                                                                    
 884          mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder);                                 
 885                                                                                                                    
 886          return newId;                                                                                             
 887      }                                                                                                             
 888                                                                                                                    
 889      public CellLayout getScreenWithId(long screenId) {                                                            
 890          CellLayout layout = mWorkspaceScreens.get(screenId);                                                      
 891          return layout;                                                                                            
 892      }                                                                                                             
 893                                                                                                                    
 894      public long getIdForScreen(CellLayout layout) {                                                               
 895          Iterator<Long> iter = mWorkspaceScreens.keySet().iterator();                                              
 896          while (iter.hasNext()) {                                                                                  
 897              long id = iter.next();                                                                                
 898              if (mWorkspaceScreens.get(id) == layout) {                                                            
 899                  return id;                                                                                        
 900              }                                                                                                     
 901          }                                                                                                         
 902          return -1;                                                                                                
 903      }                                                                                                             
 904                                                                                                                    
 905      public int getPageIndexForScreenId(long screenId) {                                                           
 906          return indexOfChild(mWorkspaceScreens.get(screenId));                                                     
 907      }                                                                                                             
 908                                                                                                                    
 909      public long getScreenIdForPageIndex(int index) {                                                              
 910          if (0 <= index && index < mScreenOrder.size()) {                                                          
 911              return mScreenOrder.get(index);                                                                       
 912          }                                                                                                         
 913          return -1;                                                                                                
 914      }                                                                                                             
 915                                                                                                                    
 916      ArrayList<Long> getScreenOrder() {                                                                            
 917          return mScreenOrder;                                                                                      
 918      }                                                                                                             
 919                                                                                                                    
 920      public void stripEmptyScreens() {                                                                             
 921          // Log to disk                                                                                            
 922          Launcher.addDumpLog(TAG, "11683562 - stripEmptyScreens()", true);                                         
 923 +                                                                                                                  
 924 +        if (mLauncher.isWorkspaceLoading()) {                                                                     
 925 +            // Don't strip empty screens if the workspace is still loading.                                       
 926 +            // This is dangerous and can result in data loss.                                                     
 927 +            Launcher.addDumpLog(TAG, "    - workspace loading, skip", true);                                      
 928 +            return;                                                                                               
 929 +        }                                                                                                         
 930                                                                                                                    
 931          if (isPageMoving()) {                                                                                     
 932              mStripScreensOnPageStopMoving = true;                                                                 
 933              return;                                                                                               
 934          }                                                                                                         
 935                                                                                                                    
 936          int currentPage = getNextPage();                                                                          
 937          ArrayList<Long> removeScreens = new ArrayList<Long>();                                                    
 938          for (Long id: mWorkspaceScreens.keySet()) {                                                               
 939              CellLayout cl = mWorkspaceScreens.get(id);                                                            
 940              if (id >= 0 && cl.getShortcutsAndWidgets().getChildCount() == 0) {                                    
 941                  removeScreens.add(id);                                                                            
 942              }                                                                                                     
 943          }                                                                                                         
 944                                                                                                                    
 945          // We enforce at least one page to add new items to. In the case that we remove the last                  
 946          // such screen, we convert the last screen to the empty screen                                            
 947          int minScreens = 1 + numCustomPages();                                                                    
 948                                                                                                                    
 949          int pageShift = 0;                                                                                        
 950          for (Long id: removeScreens) {                                                                            
 951              Launcher.addDumpLog(TAG, "11683562 -   removing id: " + id, true);                                    
 952              CellLayout cl = mWorkspaceScreens.get(id);                                                            
 953              mWorkspaceScreens.remove(id);                                                                         
 954              mScreenOrder.remove(id);                                                                              
 955                                                                                                                    
 956              if (getChildCount() > minScreens) {                                                                   
 957                  if (indexOfChild(cl) < currentPage) {                                                             
 958                      pageShift++;                                                                                  
 959                  }                                                                                                 
 960                  removeView(cl);                                                                                   
 961              } else {                                                                                              
 962                  // if this is the last non-custom content screen, convert it to the empty screen                  
 963                  mRemoveEmptyScreenRunnable = null;                                                                
 964                  mWorkspaceScreens.put(EXTRA_EMPTY_SCREEN_ID, cl);                                                 
 965                  mScreenOrder.add(EXTRA_EMPTY_SCREEN_ID);                                                          
 966              }                                                                                                     
 967          }                                                                                                         
 968                                                                                                                    
 969          if (!removeScreens.isEmpty()) {                                                                           
 970              // Update the model if we have changed any screens                                                    
 971              mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder);                             
 972          }                                                                                                         
 973                                                                                                                    
 974          if (pageShift >= 0) {                                                                                     
 975              setCurrentPage(currentPage - pageShift);                                                              
 976          }                                                                                                         
 977      }                                                                                                             
 978                                                                                                                    
 979      // See implementation for parameter definition.                                                               
 980      void addInScreen(View child, long container, long screenId,                                                   
 981              int x, int y, int spanX, int spanY) {                                                                 
 982          addInScreen(child, container, screenId, x, y, spanX, spanY, false, false);                                
 983      }                                                                                                             
 984                                                                                                                    
 985      // At bind time, we use the rank (screenId) to compute x and y for hotseat items.                             
 986      // See implementation for parameter definition.                                                               
 987      void addInScreenFromBind(View child, long container, long screenId, int x, int y,                             
 988              int spanX, int spanY) {                                                                               
 989          addInScreen(child, container, screenId, x, y, spanX, spanY, false, true);                                 
 990      }                                                                                                             
 991                                                                                                                    
 992      // See implementation for parameter definition.                                                               
 993      void addInScreen(View child, long container, long screenId, int x, int y, int spanX, int spanY,               
 994              boolean insert) {                                                                                     
 995          addInScreen(child, container, screenId, x, y, spanX, spanY, insert, false);                               
 996      }                                                                                                             
 997                                                                                                                    
 998      /**                                                                                                           
 999       * Adds the specified child in the specified screen. The position and dimension of                            
1000       * the child are defined by x, y, spanX and spanY.                                                            
1001       *                                                                                                            
1002       * @param child The child to add in one of the workspace's screens.                                           
1003       * @param screenId The screen in which to add the child.                                                      
1004       * @param x The X position of the child in the screen's grid.                                                 
1005       * @param y The Y position of the child in the screen's grid.                                                 
1006       * @param spanX The number of cells spanned horizontally by the child.                                        
1007       * @param spanY The number of cells spanned vertically by the child.                                          
1008       * @param insert When true, the child is inserted at the beginning of the children list.                      
1009       * @param computeXYFromRank When true, we use the rank (stored in screenId) to compute                        
1010       *                          the x and y position in which to place hotseat items. Otherwise                   
1011       *                          we use the x and y position to compute the rank.                                  
1012       */                                                                                                           
1013      void addInScreen(View child, long container, long screenId, int x, int y, int spanX, int spanY,               
1014              boolean insert, boolean computeXYFromRank) {                                                          
1015          if (container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {                                          
1016              if (getScreenWithId(screenId) == null) {                                                              
1017                  Log.e(TAG, "Skipping child, screenId " + screenId + " not found");                                
1018                  // DEBUGGING - Print out the stack trace to see where we are adding from                          
1019                  new Throwable().printStackTrace();                                                                
1020                  return;                                                                                           
1021              }                                                                                                     
1022          }                                                                                                         
1023          if (screenId == EXTRA_EMPTY_SCREEN_ID) {                                                                  
1024              // This should never happen                                                                           
1025              throw new RuntimeException("Screen id should not be EXTRA_EMPTY_SCREEN_ID");                          
1026          }                                                                                                         
1027                                                                                                                    
1028          final CellLayout layout;                                                                                  
1029          if (container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                          
1030              layout = mLauncher.getHotseat().getLayout();                                                          
1031 -            child.setOnKeyListener(null);                                                                         
1032 +            child.setOnKeyListener(new HotseatIconKeyEventListener());                                            
1033                                                                                                                    
1034              // Hide folder title in the hotseat                                                                   
1035              if (child instanceof FolderIcon) {                                                                    
1036                  ((FolderIcon) child).setTextVisible(false);                                                       
1037              }                                                                                                     
1038                                                                                                                    
1039              if (computeXYFromRank) {                                                                              
1040                  x = mLauncher.getHotseat().getCellXFromOrder((int) screenId);                                     
1041                  y = mLauncher.getHotseat().getCellYFromOrder((int) screenId);                                     
1042              } else {                                                                                              
1043                  screenId = mLauncher.getHotseat().getOrderInHotseat(x, y);                                        
1044              }                                                                                                     
1045          } else {                                                                                                  
1046              // Show folder title if not in the hotseat                                                            
1047              if (child instanceof FolderIcon) {                                                                    
1048                  ((FolderIcon) child).setTextVisible(true);                                                        
1049              }                                                                                                     
1050              layout = getScreenWithId(screenId);                                                                   
1051              child.setOnKeyListener(new IconKeyEventListener());                                                   
1052          }                                                                                                         
1053                                                                                                                    
1054          ViewGroup.LayoutParams genericLp = child.getLayoutParams();                                               
1055          CellLayout.LayoutParams lp;                                                                               
1056          if (genericLp == null || !(genericLp instanceof CellLayout.LayoutParams)) {                               
1057              lp = new CellLayout.LayoutParams(x, y, spanX, spanY);                                                 
1058          } else {                                                                                                  
1059              lp = (CellLayout.LayoutParams) genericLp;                                                             
1060              lp.cellX = x;                                                                                         
1061              lp.cellY = y;                                                                                         
1062              lp.cellHSpan = spanX;                                                                                 
1063              lp.cellVSpan = spanY;                                                                                 
1064          }                                                                                                         
1065                                                                                                                    
1066          if (spanX < 0 && spanY < 0) {                                                                             
1067              lp.isLockedToGrid = false;                                                                            
1068          }                                                                                                         
1069                                                                                                                    
1070          // Get the canonical child id to uniquely represent this view in this screen                              
1071          ItemInfo info = (ItemInfo) child.getTag();                                                                
1072          int childId = mLauncher.getViewIdForItem(info);                                                           
1073                                                                                                                    
1074          boolean markCellsAsOccupied = !(child instanceof Folder);                                                 
1075          if (!layout.addViewToCellLayout(child, insert ? 0 : -1, childId, lp, markCellsAsOccupied)) {              
1076              // TODO: This branch occurs when the workspace is adding views                                        
1077              // outside of the defined grid                                                                        
1078              // maybe we should be deleting these items from the LauncherModel?                                    
1079              Launcher.addDumpLog(TAG, "Failed to add to item at (" + lp.cellX + "," + lp.cellY + ") to CellLayout",🔵
1080          }                                                                                                         
1081                                                                                                                    
1082          if (!(child instanceof Folder)) {                                                                         
1083              child.setHapticFeedbackEnabled(false);                                                                
1084              child.setOnLongClickListener(mLongClickListener);                                                     
1085          }                                                                                                         
1086          if (child instanceof DropTarget) {                                                                        
1087              mDragController.addDropTarget((DropTarget) child);                                                    
1088          }                                                                                                         
1089      }                                                                                                             
1090                                                                                                                    
1091      /**                                                                                                           
1092       * Called directly from a CellLayout (not by the framework), after we've been added as a                      
1093       * listener via setOnInterceptTouchEventListener(). This allows us to tell the CellLayout                     
1094       * that it should intercept touch events, which is not something that is normally supported.                  
1095       */                                                                                                           
1096      @Override                                                                                                     
1097      public boolean onTouch(View v, MotionEvent event) {                                                           
1098 -        return (isSmall() || !isFinishedSwitchingState())                                                         
1099 -                || (!isSmall() && indexOfChild(v) != mCurrentPage);                                               
1100 +        return (workspaceInModalState() || !isFinishedSwitchingState())                                           
1101 +                || (!workspaceInModalState() && indexOfChild(v) != mCurrentPage);                                 
1102      }                                                                                                             
1103                                                                                                                    
1104      public boolean isSwitchingState() {                                                                           
1105          return mIsSwitchingState;                                                                                 
1106      }                                                                                                             
1107                                                                                                                    
1108      /** This differs from isSwitchingState in that we take into account how far the transition                    
1109       *  has completed. */                                                                                         
1110      public boolean isFinishedSwitchingState() {                                                                   
1111          return !mIsSwitchingState || (mTransitionProgress > 0.5f);                                                
1112      }                                                                                                             
1113                                                                                                                    
1114      protected void onWindowVisibilityChanged (int visibility) {                                                   
1115          mLauncher.onWindowVisibilityChanged(visibility);                                                          
1116      }                                                                                                             
1117                                                                                                                    
1118      @Override                                                                                                     
1119      public boolean dispatchUnhandledMove(View focused, int direction) {                                           
1120 -        if (isSmall() || !isFinishedSwitchingState()) {                                                           
1121 +        if (workspaceInModalState() || !isFinishedSwitchingState()) {                                             
1122              // when the home screens are shrunken, shouldn't allow side-scrolling                                 
1123              return false;                                                                                         
1124          }                                                                                                         
1125          return super.dispatchUnhandledMove(focused, direction);                                                   
1126      }                                                                                                             
1127                                                                                                                    
1128      @Override                                                                                                     
1129      public boolean onInterceptTouchEvent(MotionEvent ev) {                                                        
1130          switch (ev.getAction() & MotionEvent.ACTION_MASK) {                                                       
1131          case MotionEvent.ACTION_DOWN:                                                                             
1132              mXDown = ev.getX();                                                                                   
1133              mYDown = ev.getY();                                                                                   
1134              mTouchDownTime = System.currentTimeMillis();                                                          
1135              break;                                                                                                
1136          case MotionEvent.ACTION_POINTER_UP:                                                                       
1137          case MotionEvent.ACTION_UP:                                                                               
1138              if (mTouchState == TOUCH_STATE_REST) {                                                                
1139                  final CellLayout currentPage = (CellLayout) getChildAt(mCurrentPage);                             
1140 -                if (!currentPage.lastDownOnOccupiedCell()) {                                                      
1141 +                if (currentPage != null && !currentPage.lastDownOnOccupiedCell()) {                               
1142                      onWallpaperTap(ev);                                                                           
1143                  }                                                                                                 
1144              }                                                                                                     
1145          }                                                                                                         
1146          return super.onInterceptTouchEvent(ev);                                                                   
1147 +    }                                                                                                             
1148 +                                                                                                                  
1149 +    @Override                                                                                                     
1150 +    public boolean onGenericMotionEvent(MotionEvent event) {                                                      
1151 +        // Ignore pointer scroll events if the custom content doesn't allow scrolling.                            
1152 +        if ((getScreenIdForPageIndex(getCurrentPage()) == CUSTOM_CONTENT_SCREEN_ID)                               
1153 +                && (mCustomContentCallbacks != null)                                                              
1154 +                && !mCustomContentCallbacks.isScrollingAllowed()) {                                               
1155 +            return false;                                                                                         
1156 +        }                                                                                                         
1157 +        return super.onGenericMotionEvent(event);                                                                 
1158      }                                                                                                             
1159                                                                                                                    
1160      protected void reinflateWidgetsIfNecessary() {                                                                
1161          final int clCount = getChildCount();                                                                      
1162          for (int i = 0; i < clCount; i++) {                                                                       
1163              CellLayout cl = (CellLayout) getChildAt(i);                                                           
1164              ShortcutAndWidgetContainer swc = cl.getShortcutsAndWidgets();                                         
1165              final int itemCount = swc.getChildCount();                                                            
1166              for (int j = 0; j < itemCount; j++) {                                                                 
1167                  View v = swc.getChildAt(j);                                                                       
1168                                                                                                                    
1169 -                if (v.getTag() instanceof LauncherAppWidgetInfo) {                                                
1170 +                if (v != null  && v.getTag() instanceof LauncherAppWidgetInfo) {                                  
1171                      LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) v.getTag();                              
1172                      LauncherAppWidgetHostView lahv = (LauncherAppWidgetHostView) info.hostView;                   
1173 -                    if (lahv != null && lahv.orientationChangedSincedInflation()) {                               
1174 +                    if (lahv != null && lahv.isReinflateRequired()) {                                             
1175                          mLauncher.removeAppWidget(info);                                                          
1176                          // Remove the current widget which is inflated with the wrong orientation                 
1177                          cl.removeView(lahv);                                                                      
1178                          mLauncher.bindAppWidget(info);                                                            
1179                      }                                                                                             
1180                  }                                                                                                 
1181              }                                                                                                     
1182          }                                                                                                         
1183      }                                                                                                             
1184                                                                                                                    
1185      @Override                                                                                                     
1186      protected void determineScrollingStart(MotionEvent ev) {                                                      
1187          if (!isFinishedSwitchingState()) return;                                                                  
1188                                                                                                                    
1189          float deltaX = ev.getX() - mXDown;                                                                        
1190          float absDeltaX = Math.abs(deltaX);                                                                       
1191          float absDeltaY = Math.abs(ev.getY() - mYDown);                                                           
1192                                                                                                                    
1193          if (Float.compare(absDeltaX, 0f) == 0) return;                                                            
1194                                                                                                                    
1195          float slope = absDeltaY / absDeltaX;                                                                      
1196          float theta = (float) Math.atan(slope);                                                                   
1197                                                                                                                    
1198          if (absDeltaX > mTouchSlop || absDeltaY > mTouchSlop) {                                                   
1199              cancelCurrentPageLongPress();                                                                         
1200          }                                                                                                         
1201                                                                                                                    
1202          boolean passRightSwipesToCustomContent =                                                                  
1203                  (mTouchDownTime - mCustomContentShowTime) > CUSTOM_CONTENT_GESTURE_DELAY;                         
1204                                                                                                                    
1205          boolean swipeInIgnoreDirection = isLayoutRtl() ? deltaX < 0 : deltaX > 0;                                 
1206 -        if (swipeInIgnoreDirection && getScreenIdForPageIndex(getCurrentPage()) ==                                
1207 -                CUSTOM_CONTENT_SCREEN_ID && passRightSwipesToCustomContent) {                                     
1208 +        boolean onCustomContentScreen =                                                                           
1209 +                getScreenIdForPageIndex(getCurrentPage()) == CUSTOM_CONTENT_SCREEN_ID;                            
1210 +        if (swipeInIgnoreDirection && onCustomContentScreen && passRightSwipesToCustomContent) {                  
1211              // Pass swipes to the right to the custom content page.                                               
1212 +            return;                                                                                               
1213 +        }                                                                                                         
1214 +                                                                                                                  
1215 +        if (onCustomContentScreen && (mCustomContentCallbacks != null)                                            
1216 +                && !mCustomContentCallbacks.isScrollingAllowed()) {                                               
1217 +            // Don't allow workspace scrolling if the current custom content screen doesn't allow                 
1218 +            // scrolling.                                                                                         
1219              return;                                                                                               
1220          }                                                                                                         
1221                                                                                                                    
1222          if (theta > MAX_SWIPE_ANGLE) {                                                                            
1223              // Above MAX_SWIPE_ANGLE, we don't want to ever start scrolling the workspace                         
1224              return;                                                                                               
1225          } else if (theta > START_DAMPING_TOUCH_SLOP_ANGLE) {                                                      
1226              // Above START_DAMPING_TOUCH_SLOP_ANGLE and below MAX_SWIPE_ANGLE, we want to                         
1227              // increase the touch slop to make it harder to begin scrolling the workspace. This                   
1228              // results in vertically scrolling widgets to more easily. The higher the angle, the                  
1229              // more we increase touch slop.                                                                       
1230              theta -= START_DAMPING_TOUCH_SLOP_ANGLE;                                                              
1231              float extraRatio = (float)                                                                            
1232                      Math.sqrt((theta / (MAX_SWIPE_ANGLE - START_DAMPING_TOUCH_SLOP_ANGLE)));                      
1233              super.determineScrollingStart(ev, 1 + TOUCH_SLOP_DAMPING_FACTOR * extraRatio);                        
1234          } else {                                                                                                  
1235              // Below START_DAMPING_TOUCH_SLOP_ANGLE, we don't do anything special                                 
1236              super.determineScrollingStart(ev);                                                                    
1237          }                                                                                                         
1238      }                                                                                                             
1239                                                                                                                    
1240      protected void onPageBeginMoving() {                                                                          
1241          super.onPageBeginMoving();                                                                                
1242                                                                                                                    
1243          if (isHardwareAccelerated()) {                                                                            
1244              updateChildrenLayersEnabled(false);                                                                   
1245          } else {                                                                                                  
1246              if (mNextPage != INVALID_PAGE) {                                                                      
1247                  // we're snapping to a particular screen                                                          
1248                  enableChildrenCache(mCurrentPage, mNextPage);                                                     
1249              } else {                                                                                              
1250                  // this is when user is actively dragging a particular screen, they might                         
1251                  // swipe it either left or right (but we won't advance by more than one screen)                   
1252                  enableChildrenCache(mCurrentPage - 1, mCurrentPage + 1);                                          
1253              }                                                                                                     
1254          }                                                                                                         
1255 -                                                                                                                  
1256 -        // If we are not fading in adjacent screens, we still need to restore the alpha in case the               
1257 -        // user scrolls while we are transitioning (should not affect dispatchDraw optimizations)                 
1258 -        if (!mWorkspaceFadeInAdjacentScreens) {                                                                   
1259 -            for (int i = 0; i < getChildCount(); ++i) {                                                           
1260 -                ((CellLayout) getPageAt(i)).setShortcutAndWidgetAlpha(1f);                                        
1261 -            }                                                                                                     
1262 -        }                                                                                                         
1263      }                                                                                                             
1264                                                                                                                    
1265      protected void onPageEndMoving() {                                                                            
1266          super.onPageEndMoving();                                                                                  
1267                                                                                                                    
1268          if (isHardwareAccelerated()) {                                                                            
1269              updateChildrenLayersEnabled(false);                                                                   
1270          } else {                                                                                                  
1271              clearChildrenCache();                                                                                 
1272          }                                                                                                         
1273                                                                                                                    
1274          if (mDragController.isDragging()) {                                                                       
1275 -            if (isSmall()) {                                                                                      
1276 +            if (workspaceInModalState()) {                                                                        
1277                  // If we are in springloaded mode, then force an event to check if the current touch              
1278                  // is under a new page (to scroll to)                                                             
1279                  mDragController.forceTouchMove();                                                                 
1280              }                                                                                                     
1281          }                                                                                                         
1282                                                                                                                    
1283          if (mDelayedResizeRunnable != null) {                                                                     
1284              mDelayedResizeRunnable.run();                                                                         
1285              mDelayedResizeRunnable = null;                                                                        
1286          }                                                                                                         
1287                                                                                                                    
1288          if (mDelayedSnapToPageRunnable != null) {                                                                 
1289              mDelayedSnapToPageRunnable.run();                                                                     
1290              mDelayedSnapToPageRunnable = null;                                                                    
1291          }                                                                                                         
1292          if (mStripScreensOnPageStopMoving) {                                                                      
1293              stripEmptyScreens();                                                                                  
1294              mStripScreensOnPageStopMoving = false;                                                                
1295          }                                                                                                         
1296      }                                                                                                             
1297                                                                                                                    
1298      @Override                                                                                                     
1299      protected void notifyPageSwitchListener() {                                                                   
1300          super.notifyPageSwitchListener();                                                                         
1301          Launcher.setScreen(getNextPage());                                                                        
1302                                                                                                                    
1303          if (hasCustomContent() && getNextPage() == 0 && !mCustomContentShowing) {                                 
1304              mCustomContentShowing = true;                                                                         
1305              if (mCustomContentCallbacks != null) {                                                                
1306 -                mCustomContentCallbacks.onShow();                                                                 
1307 +                mCustomContentCallbacks.onShow(false);                                                            
1308                  mCustomContentShowTime = System.currentTimeMillis();                                              
1309                  mLauncher.updateVoiceButtonProxyVisible(false);                                                   
1310              }                                                                                                     
1311          } else if (hasCustomContent() && getNextPage() != 0 && mCustomContentShowing) {                           
1312              mCustomContentShowing = false;                                                                        
1313              if (mCustomContentCallbacks != null) {                                                                
1314                  mCustomContentCallbacks.onHide();                                                                 
1315                  mLauncher.resetQSBScroll();                                                                       
1316                  mLauncher.updateVoiceButtonProxyVisible(false);                                                   
1317              }                                                                                                     
1318 -        }                                                                                                         
1319 -        if (getPageIndicator() != null) {                                                                         
1320 -            getPageIndicator().setContentDescription(getPageIndicatorDescription());                              
1321          }                                                                                                         
1322      }                                                                                                             
1323                                                                                                                    
1324      protected CustomContentCallbacks getCustomContentCallbacks() {                                                
1325          return mCustomContentCallbacks;                                                                           
1326      }                                                                                                             
1327                                                                                                                    
1328      protected void setWallpaperDimension() {                                                                      
1329          new AsyncTask<Void, Void, Void>() {                                                                       
1330              public Void doInBackground(Void ... args) {                                                           
1331                  String spKey = WallpaperCropActivity.getSharedPreferencesKey();                                   
1332                  SharedPreferences sp =                                                                            
1333                          mLauncher.getSharedPreferences(spKey, Context.MODE_MULTI_PROCESS);                        
1334                  LauncherWallpaperPickerActivity.suggestWallpaperDimension(mLauncher.getResources(),               
1335 -                        sp, mLauncher.getWindowManager(), mWallpaperManager);                                     
1336 +                        sp, mLauncher.getWindowManager(), mWallpaperManager,                                      
1337 +                        mLauncher.overrideWallpaperDimensions());                                                 
1338                  return null;                                                                                      
1339              }                                                                                                     
1340          }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);                                         
1341      }                                                                                                             
1342                                                                                                                    
1343      protected void snapToPage(int whichPage, Runnable r) {                                                        
1344          snapToPage(whichPage, SLOW_PAGE_SNAP_ANIMATION_DURATION, r);                                              
1345      }                                                                                                             
1346                                                                                                                    
1347      protected void snapToPage(int whichPage, int duration, Runnable r) {                                          
1348          if (mDelayedSnapToPageRunnable != null) {                                                                 
1349              mDelayedSnapToPageRunnable.run();                                                                     
1350          }                                                                                                         
1351          mDelayedSnapToPageRunnable = r;                                                                           
1352          snapToPage(whichPage, duration);                                                                          
1353 +    }                                                                                                             
1354 +                                                                                                                  
1355 +    public void snapToScreenId(long screenId) {                                                                   
1356 +        snapToScreenId(screenId, null);                                                                           
1357      }                                                                                                             
1358                                                                                                                    
1359      protected void snapToScreenId(long screenId, Runnable r) {                                                    
1360          snapToPage(getPageIndexForScreenId(screenId), r);                                                         
1361      }                                                                                                             
1362                                                                                                                    
1363      class WallpaperOffsetInterpolator implements Choreographer.FrameCallback {                                    
1364          float mFinalOffset = 0.0f;                                                                                
1365          float mCurrentOffset = 0.5f; // to force an initial update                                                
1366          boolean mWaitingForUpdate;                                                                                
1367          Choreographer mChoreographer;                                                                             
1368          Interpolator mInterpolator;                                                                               
1369          boolean mAnimating;                                                                                       
1370          long mAnimationStartTime;                                                                                 
1371          float mAnimationStartOffset;                                                                              
1372          private final int ANIMATION_DURATION = 250;                                                               
1373          // Don't use all the wallpaper for parallax until you have at least this many pages                       
1374          private final int MIN_PARALLAX_PAGE_SPAN = 3;                                                             
1375          int mNumScreens;                                                                                          
1376                                                                                                                    
1377          public WallpaperOffsetInterpolator() {                                                                    
1378              mChoreographer = Choreographer.getInstance();                                                         
1379              mInterpolator = new DecelerateInterpolator(1.5f);                                                     
1380          }                                                                                                         
1381                                                                                                                    
1382          @Override                                                                                                 
1383          public void doFrame(long frameTimeNanos) {                                                                
1384              updateOffset(false);                                                                                  
1385          }                                                                                                         
1386                                                                                                                    
1387          private void updateOffset(boolean force) {                                                                
1388              if (mWaitingForUpdate || force) {                                                                     
1389                  mWaitingForUpdate = false;                                                                        
1390                  if (computeScrollOffset() && mWindowToken != null) {                                              
1391                      try {                                                                                         
1392                          mWallpaperManager.setWallpaperOffsets(mWindowToken,                                       
1393                                  mWallpaperOffset.getCurrX(), 0.5f);                                               
1394                          setWallpaperOffsetSteps();                                                                
1395                      } catch (IllegalArgumentException e) {                                                        
1396                          Log.e(TAG, "Error updating wallpaper offset: " + e);                                      
1397                      }                                                                                             
1398                  }                                                                                                 
1399              }                                                                                                     
1400          }                                                                                                         
1401                                                                                                                    
1402          public boolean computeScrollOffset() {                                                                    
1403              final float oldOffset = mCurrentOffset;                                                               
1404              if (mAnimating) {                                                                                     
1405                  long durationSinceAnimation = System.currentTimeMillis() - mAnimationStartTime;                   
1406                  float t0 = durationSinceAnimation / (float) ANIMATION_DURATION;                                   
1407                  float t1 = mInterpolator.getInterpolation(t0);                                                    
1408                  mCurrentOffset = mAnimationStartOffset +                                                          
1409                          (mFinalOffset - mAnimationStartOffset) * t1;                                              
1410                  mAnimating = durationSinceAnimation < ANIMATION_DURATION;                                         
1411              } else {                                                                                              
1412                  mCurrentOffset = mFinalOffset;                                                                    
1413              }                                                                                                     
1414                                                                                                                    
1415              if (Math.abs(mCurrentOffset - mFinalOffset) > 0.0000001f) {                                           
1416                  scheduleUpdate();                                                                                 
1417              }                                                                                                     
1418              if (Math.abs(oldOffset - mCurrentOffset) > 0.0000001f) {                                              
1419                  return true;                                                                                      
1420              }                                                                                                     
1421              return false;                                                                                         
1422          }                                                                                                         
1423                                                                                                                    
1424          private float wallpaperOffsetForCurrentScroll() {                                                         
1425              if (getChildCount() <= 1) {                                                                           
1426                  return 0;                                                                                         
1427              }                                                                                                     
1428                                                                                                                    
1429              // Exclude the leftmost page                                                                          
1430              int emptyExtraPages = numEmptyScreensToIgnore();                                                      
1431              int firstIndex = numCustomPages();                                                                    
1432              // Exclude the last extra empty screen (if we have > MIN_PARALLAX_PAGE_SPAN pages)                    
1433              int lastIndex = getChildCount() - 1 - emptyExtraPages;                                                
1434              if (isLayoutRtl()) {                                                                                  
1435                  int temp = firstIndex;                                                                            
1436                  firstIndex = lastIndex;                                                                           
1437                  lastIndex = temp;                                                                                 
1438              }                                                                                                     
1439                                                                                                                    
1440              int firstPageScrollX = getScrollForPage(firstIndex);                                                  
1441              int scrollRange = getScrollForPage(lastIndex) - firstPageScrollX;                                     
1442              if (scrollRange == 0) {                                                                               
1443                  return 0;                                                                                         
1444              } else {                                                                                              
1445                  // TODO: do different behavior if it's  a live wallpaper?                                         
1446                  // Sometimes the left parameter of the pages is animated during a layout transition;              
1447                  // this parameter offsets it to keep the wallpaper from animating as well                         
1448                  int adjustedScroll =                                                                              
1449                          getScrollX() - firstPageScrollX - getLayoutTransitionOffsetForPage(0);                    
1450                  float offset = Math.min(1, adjustedScroll / (float) scrollRange);                                 
1451                  offset = Math.max(0, offset);                                                                     
1452                  // Don't use up all the wallpaper parallax until you have at least                                
1453                  // MIN_PARALLAX_PAGE_SPAN pages                                                                   
1454                  int numScrollingPages = getNumScreensExcludingEmptyAndCustom();                                   
1455                  int parallaxPageSpan;                                                                             
1456                  if (mWallpaperIsLiveWallpaper) {                                                                  
1457                      parallaxPageSpan = numScrollingPages - 1;                                                     
1458                  } else {                                                                                          
1459                      parallaxPageSpan = Math.max(MIN_PARALLAX_PAGE_SPAN, numScrollingPages - 1);                   
1460                  }                                                                                                 
1461                  mNumPagesForWallpaperParallax = parallaxPageSpan;                                                 
1462                                                                                                                    
1463                  // On RTL devices, push the wallpaper offset to the right if we don't have enough                 
1464                  // pages (ie if numScrollingPages < MIN_PARALLAX_PAGE_SPAN)                                       
1465                  int padding = isLayoutRtl() ? parallaxPageSpan - numScrollingPages + 1 : 0;                       
1466                  return offset * (padding + numScrollingPages - 1) / parallaxPageSpan;                             
1467              }                                                                                                     
1468          }                                                                                                         
1469                                                                                                                    
1470          private int numEmptyScreensToIgnore() {                                                                   
1471              int numScrollingPages = getChildCount() - numCustomPages();                                           
1472              if (numScrollingPages >= MIN_PARALLAX_PAGE_SPAN && hasExtraEmptyScreen()) {                           
1473                  return 1;                                                                                         
1474              } else {                                                                                              
1475                  return 0;                                                                                         
1476              }                                                                                                     
1477          }                                                                                                         
1478                                                                                                                    
1479          private int getNumScreensExcludingEmptyAndCustom() {                                                      
1480              int numScrollingPages = getChildCount() - numEmptyScreensToIgnore() - numCustomPages();               
1481              return numScrollingPages;                                                                             
1482          }                                                                                                         
1483                                                                                                                    
1484          public void syncWithScroll() {                                                                            
1485              float offset = wallpaperOffsetForCurrentScroll();                                                     
1486              mWallpaperOffset.setFinalX(offset);                                                                   
1487              updateOffset(true);                                                                                   
1488          }                                                                                                         
1489                                                                                                                    
1490          public float getCurrX() {                                                                                 
1491              return mCurrentOffset;                                                                                
1492          }                                                                                                         
1493                                                                                                                    
1494          public float getFinalX() {                                                                                
1495              return mFinalOffset;                                                                                  
1496          }                                                                                                         
1497                                                                                                                    
1498          private void animateToFinal() {                                                                           
1499              mAnimating = true;                                                                                    
1500              mAnimationStartOffset = mCurrentOffset;                                                               
1501              mAnimationStartTime = System.currentTimeMillis();                                                     
1502          }                                                                                                         
1503                                                                                                                    
1504          private void setWallpaperOffsetSteps() {                                                                  
1505              // Set wallpaper offset steps (1 / (number of screens - 1))                                           
1506              float xOffset = 1.0f / mNumPagesForWallpaperParallax;                                                 
1507              if (xOffset != mLastSetWallpaperOffsetSteps) {                                                        
1508                  mWallpaperManager.setWallpaperOffsetSteps(xOffset, 1.0f);                                         
1509                  mLastSetWallpaperOffsetSteps = xOffset;                                                           
1510              }                                                                                                     
1511          }                                                                                                         
1512                                                                                                                    
1513          public void setFinalX(float x) {                                                                          
1514              scheduleUpdate();                                                                                     
1515              mFinalOffset = Math.max(0f, Math.min(x, 1.0f));                                                       
1516              if (getNumScreensExcludingEmptyAndCustom() != mNumScreens) {                                          
1517                  if (mNumScreens > 0) {                                                                            
1518                      // Don't animate if we're going from 0 screens                                                
1519                      animateToFinal();                                                                             
1520                  }                                                                                                 
1521                  mNumScreens = getNumScreensExcludingEmptyAndCustom();                                             
1522              }                                                                                                     
1523          }                                                                                                         
1524                                                                                                                    
1525          private void scheduleUpdate() {                                                                           
1526              if (!mWaitingForUpdate) {                                                                             
1527                  mChoreographer.postFrameCallback(this);                                                           
1528                  mWaitingForUpdate = true;                                                                         
1529              }                                                                                                     
1530          }                                                                                                         
1531                                                                                                                    
1532          public void jumpToFinal() {                                                                               
1533              mCurrentOffset = mFinalOffset;                                                                        
1534          }                                                                                                         
1535      }                                                                                                             
1536                                                                                                                    
1537      @Override                                                                                                     
1538      public void computeScroll() {                                                                                 
1539          super.computeScroll();                                                                                    
1540          mWallpaperOffset.syncWithScroll();                                                                        
1541      }                                                                                                             
1542                                                                                                                    
1543 +    @Override                                                                                                     
1544 +    public void announceForAccessibility(CharSequence text) {                                                     
1545 +        // Don't announce if apps is on top of us.                                                                
1546 +        if (!mLauncher.isAllAppsVisible()) {                                                                      
1547 +            super.announceForAccessibility(text);                                                                 
1548 +        }                                                                                                         
1549 +    }                                                                                                             
1550 +                                                                                                                  
1551      void showOutlines() {                                                                                         
1552 -        if (!isSmall() && !mIsSwitchingState) {                                                                   
1553 +        if (!workspaceInModalState() && !mIsSwitchingState) {                                                     
1554              if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();              
1555              if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();                
1556              mChildrenOutlineFadeInAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 1.0f);      
1557              mChildrenOutlineFadeInAnimation.setDuration(CHILDREN_OUTLINE_FADE_IN_DURATION);                       
1558              mChildrenOutlineFadeInAnimation.start();                                                              
1559          }                                                                                                         
1560      }                                                                                                             
1561                                                                                                                    
1562      void hideOutlines() {                                                                                         
1563 -        if (!isSmall() && !mIsSwitchingState) {                                                                   
1564 +        if (!workspaceInModalState() && !mIsSwitchingState) {                                                     
1565              if (mChildrenOutlineFadeInAnimation != null) mChildrenOutlineFadeInAnimation.cancel();                
1566              if (mChildrenOutlineFadeOutAnimation != null) mChildrenOutlineFadeOutAnimation.cancel();              
1567              mChildrenOutlineFadeOutAnimation = LauncherAnimUtils.ofFloat(this, "childrenOutlineAlpha", 0.0f);     
1568              mChildrenOutlineFadeOutAnimation.setDuration(CHILDREN_OUTLINE_FADE_OUT_DURATION);                     
1569              mChildrenOutlineFadeOutAnimation.setStartDelay(CHILDREN_OUTLINE_FADE_OUT_DELAY);                      
1570              mChildrenOutlineFadeOutAnimation.start();                                                             
1571          }                                                                                                         
1572      }                                                                                                             
1573                                                                                                                    
1574      public void showOutlinesTemporarily() {                                                                       
1575          if (!mIsPageMoving && !isTouchActive()) {                                                                 
1576              snapToPage(mCurrentPage);                                                                             
1577          }                                                                                                         
1578      }                                                                                                             
1579                                                                                                                    
1580      public void setChildrenOutlineAlpha(float alpha) {                                                            
1581          mChildrenOutlineAlpha = alpha;                                                                            
1582          for (int i = 0; i < getChildCount(); i++) {                                                               
1583              CellLayout cl = (CellLayout) getChildAt(i);                                                           
1584              cl.setBackgroundAlpha(alpha);                                                                         
1585          }                                                                                                         
1586      }                                                                                                             
1587                                                                                                                    
1588      public float getChildrenOutlineAlpha() {                                                                      
1589          return mChildrenOutlineAlpha;                                                                             
1590      }                                                                                                             
1591                                                                                                                    
1592 -    void disableBackground() {                                                                                    
1593 -        mDrawBackground = false;                                                                                  
1594 -    }                                                                                                             
1595 -    void enableBackground() {                                                                                     
1596 -        mDrawBackground = true;                                                                                   
1597 -    }                                                                                                             
1598 -                                                                                                                  
1599      private void animateBackgroundGradient(float finalAlpha, boolean animated) {                                  
1600 -        if (mBackground == null) return;                                                                          
1601 +        final DragLayer dragLayer = mLauncher.getDragLayer();                                                     
1602 +                                                                                                                  
1603          if (mBackgroundFadeInAnimation != null) {                                                                 
1604              mBackgroundFadeInAnimation.cancel();                                                                  
1605              mBackgroundFadeInAnimation = null;                                                                    
1606          }                                                                                                         
1607          if (mBackgroundFadeOutAnimation != null) {                                                                
1608              mBackgroundFadeOutAnimation.cancel();                                                                 
1609              mBackgroundFadeOutAnimation = null;                                                                   
1610          }                                                                                                         
1611 -        float startAlpha = getBackgroundAlpha();                                                                  
1612 +        float startAlpha = dragLayer.getBackgroundAlpha();                                                        
1613          if (finalAlpha != startAlpha) {                                                                           
1614              if (animated) {                                                                                       
1615                  mBackgroundFadeOutAnimation =                                                                     
1616                          LauncherAnimUtils.ofFloat(this, startAlpha, finalAlpha);                                  
1617                  mBackgroundFadeOutAnimation.addUpdateListener(new AnimatorUpdateListener() {                      
1618                      public void onAnimationUpdate(ValueAnimator animation) {                                      
1619 -                        setBackgroundAlpha(((Float) animation.getAnimatedValue()).floatValue());                  
1620 +                        dragLayer.setBackgroundAlpha(                                                             
1621 +                                ((Float)animation.getAnimatedValue()).floatValue());                              
1622                      }                                                                                             
1623                  });                                                                                               
1624                  mBackgroundFadeOutAnimation.setInterpolator(new DecelerateInterpolator(1.5f));                    
1625                  mBackgroundFadeOutAnimation.setDuration(BACKGROUND_FADE_OUT_DURATION);                            
1626                  mBackgroundFadeOutAnimation.start();                                                              
1627              } else {                                                                                              
1628 -                setBackgroundAlpha(finalAlpha);                                                                   
1629 -            }                                                                                                     
1630 -        }                                                                                                         
1631 -    }                                                                                                             
1632 -                                                                                                                  
1633 -    public void setBackgroundAlpha(float alpha) {                                                                 
1634 -        if (alpha != mBackgroundAlpha) {                                                                          
1635 -            mBackgroundAlpha = alpha;                                                                             
1636 -            invalidate();                                                                                         
1637 -        }                                                                                                         
1638 -    }                                                                                                             
1639 -                                                                                                                  
1640 -    public float getBackgroundAlpha() {                                                                           
1641 -        return mBackgroundAlpha;                                                                                  
1642 +                dragLayer.setBackgroundAlpha(finalAlpha);                                                         
1643 +            }                                                                                                     
1644 +        }                                                                                                         
1645      }                                                                                                             
1646                                                                                                                    
1647      float backgroundAlphaInterpolator(float r) {                                                                  
1648          float pivotA = 0.1f;                                                                                      
1649          float pivotB = 0.4f;                                                                                      
1650          if (r < pivotA) {                                                                                         
1651              return 0;                                                                                             
1652          } else if (r > pivotB) {                                                                                  
1653              return 1.0f;                                                                                          
1654          } else {                                                                                                  
1655              return (r - pivotA)/(pivotB - pivotA);                                                                
1656          }                                                                                                         
1657      }                                                                                                             
1658                                                                                                                    
1659      private void updatePageAlphaValues(int screenCenter) {                                                        
1660          boolean isInOverscroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX;                                  
1661          if (mWorkspaceFadeInAdjacentScreens &&                                                                    
1662 -                mState == State.NORMAL &&                                                                         
1663 +                !workspaceInModalState() &&                                                                       
1664                  !mIsSwitchingState &&                                                                             
1665                  !isInOverscroll) {                                                                                
1666              for (int i = numCustomPages(); i < getChildCount(); i++) {                                            
1667                  CellLayout child = (CellLayout) getChildAt(i);                                                    
1668                  if (child != null) {                                                                              
1669                      float scrollProgress = getScrollProgress(screenCenter, child, i);                             
1670                      float alpha = 1 - Math.abs(scrollProgress);                                                   
1671                      child.getShortcutsAndWidgets().setAlpha(alpha);                                               
1672 +                    //child.setBackgroundAlphaMultiplier(1 - alpha);                                              
1673                  }                                                                                                 
1674              }                                                                                                     
1675          }                                                                                                         
1676      }                                                                                                             
1677                                                                                                                    
1678      private void setChildrenBackgroundAlphaMultipliers(float a) {                                                 
1679          for (int i = 0; i < getChildCount(); i++) {                                                               
1680              CellLayout child = (CellLayout) getChildAt(i);                                                        
1681              child.setBackgroundAlphaMultiplier(a);                                                                
1682          }                                                                                                         
1683      }                                                                                                             
1684                                                                                                                    
1685      public boolean hasCustomContent() {                                                                           
1686          return (mScreenOrder.size() > 0 && mScreenOrder.get(0) == CUSTOM_CONTENT_SCREEN_ID);                      
1687      }                                                                                                             
1688                                                                                                                    
1689      public int numCustomPages() {                                                                                 
1690          return hasCustomContent() ? 1 : 0;                                                                        
1691      }                                                                                                             
1692                                                                                                                    
1693      public boolean isOnOrMovingToCustomContent() {                                                                
1694          return hasCustomContent() && getNextPage() == 0;                                                          
1695      }                                                                                                             
1696                                                                                                                    
1697      private void updateStateForCustomContent(int screenCenter) {                                                  
1698          float translationX = 0;                                                                                   
1699          float progress = 0;                                                                                       
1700          if (hasCustomContent()) {                                                                                 
1701              int index = mScreenOrder.indexOf(CUSTOM_CONTENT_SCREEN_ID);                                           
1702                                                                                                                    
1703              int scrollDelta = getScrollX() - getScrollForPage(index) -                                            
1704                      getLayoutTransitionOffsetForPage(index);                                                      
1705              float scrollRange = getScrollForPage(index + 1) - getScrollForPage(index);                            
1706              translationX = scrollRange - scrollDelta;                                                             
1707              progress = (scrollRange - scrollDelta) / scrollRange;                                                 
1708                                                                                                                    
1709              if (isLayoutRtl()) {                                                                                  
1710                  translationX = Math.min(0, translationX);                                                         
1711              } else {                                                                                              
1712                  translationX = Math.max(0, translationX);                                                         
1713              }                                                                                                     
1714              progress = Math.max(0, progress);                                                                     
1715          }                                                                                                         
1716                                                                                                                    
1717          if (Float.compare(progress, mLastCustomContentScrollProgress) == 0) return;                               
1718                                                                                                                    
1719          CellLayout cc = mWorkspaceScreens.get(CUSTOM_CONTENT_SCREEN_ID);                                          
1720 -        if (progress > 0 && cc.getVisibility() != VISIBLE && !isSmall()) {                                        
1721 +        if (progress > 0 && cc.getVisibility() != VISIBLE && !workspaceInModalState()) {                          
1722              cc.setVisibility(VISIBLE);                                                                            
1723          }                                                                                                         
1724                                                                                                                    
1725          mLastCustomContentScrollProgress = progress;                                                              
1726                                                                                                                    
1727 -        setBackgroundAlpha(progress * 0.8f);                                                                      
1728 +        mLauncher.getDragLayer().setBackgroundAlpha(progress * 0.8f);                                             
1729                                                                                                                    
1730          if (mLauncher.getHotseat() != null) {                                                                     
1731              mLauncher.getHotseat().setTranslationX(translationX);                                                 
1732          }                                                                                                         
1733                                                                                                                    
1734          if (getPageIndicator() != null) {                                                                         
1735              getPageIndicator().setTranslationX(translationX);                                                     
1736          }                                                                                                         
1737                                                                                                                    
1738          if (mCustomContentCallbacks != null) {                                                                    
1739              mCustomContentCallbacks.onScrollProgressChanged(progress);                                            
1740          }                                                                                                         
1741      }                                                                                                             
1742                                                                                                                    
1743      @Override                                                                                                     
1744      protected OnClickListener getPageIndicatorClickListener() {                                                   
1745          AccessibilityManager am = (AccessibilityManager)                                                          
1746                  getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);                                     
1747          if (!am.isTouchExplorationEnabled()) {                                                                    
1748              return null;                                                                                          
1749          }                                                                                                         
1750          OnClickListener listener = new OnClickListener() {                                                        
1751              @Override                                                                                             
1752              public void onClick(View arg0) {                                                                      
1753                  enterOverviewMode();                                                                              
1754              }                                                                                                     
1755          };                                                                                                        
1756          return listener;                                                                                          
1757      }                                                                                                             
1758                                                                                                                    
1759      @Override                                                                                                     
1760      protected void screenScrolled(int screenCenter) {                                                             
1761          final boolean isRtl = isLayoutRtl();                                                                      
1762          super.screenScrolled(screenCenter);                                                                       
1763                                                                                                                    
1764          updatePageAlphaValues(screenCenter);                                                                      
1765          updateStateForCustomContent(screenCenter);                                                                
1766          enableHwLayersOnVisiblePages();                                                                           
1767                                                                                                                    
1768 -        boolean shouldOverScroll = (mOverScrollX < 0 && (!hasCustomContent() || isLayoutRtl())) ||                
1769 -                (mOverScrollX > mMaxScrollX && (!hasCustomContent() || !isLayoutRtl()));                          
1770 +        boolean shouldOverScroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX;                                
1771                                                                                                                    
1772          if (shouldOverScroll) {                                                                                   
1773              int index = 0;                                                                                        
1774 -            float pivotX = 0f;                                                                                    
1775 -            final float leftBiasedPivot = 0.25f;                                                                  
1776 -            final float rightBiasedPivot = 0.75f;                                                                 
1777              final int lowerIndex = 0;                                                                             
1778              final int upperIndex = getChildCount() - 1;                                                           
1779                                                                                                                    
1780              final boolean isLeftPage = mOverScrollX < 0;                                                          
1781              index = (!isRtl && isLeftPage) || (isRtl && !isLeftPage) ? lowerIndex : upperIndex;                   
1782 -            pivotX = isLeftPage ? rightBiasedPivot : leftBiasedPivot;                                             
1783                                                                                                                    
1784              CellLayout cl = (CellLayout) getChildAt(index);                                                       
1785 -            float scrollProgress = getScrollProgress(screenCenter, cl, index);                                    
1786 -            cl.setOverScrollAmount(Math.abs(scrollProgress), isLeftPage);                                         
1787 -            float rotation = -WORKSPACE_OVERSCROLL_ROTATION * scrollProgress;                                     
1788 -            cl.setRotationY(rotation);                                                                            
1789 -                                                                                                                  
1790 -            if (!mOverscrollTransformsSet || Float.compare(mLastOverscrollPivotX, pivotX) != 0) {                 
1791 -                mOverscrollTransformsSet = true;                                                                  
1792 -                mLastOverscrollPivotX = pivotX;                                                                   
1793 -                cl.setCameraDistance(mDensity * mCameraDistance);                                                 
1794 -                cl.setPivotX(cl.getMeasuredWidth() * pivotX);                                                     
1795 -                cl.setPivotY(cl.getMeasuredHeight() * 0.5f);                                                      
1796 -                cl.setOverscrollTransformsDirty(true);                                                            
1797 -            }                                                                                                     
1798 +            float effect = Math.abs(mOverScrollEffect);                                                           
1799 +            cl.setOverScrollAmount(Math.abs(effect), isLeftPage);                                                 
1800 +                                                                                                                  
1801 +            mOverscrollEffectSet = true;                                                                          
1802          } else {                                                                                                  
1803 -            if (mOverscrollTransformsSet && getChildCount() > 0) {                                                
1804 -                mOverscrollTransformsSet = false;                                                                 
1805 -                ((CellLayout) getChildAt(0)).resetOverscrollTransforms();                                         
1806 -                ((CellLayout) getChildAt(getChildCount() - 1)).resetOverscrollTransforms();                       
1807 +            if (mOverscrollEffectSet && getChildCount() > 0) {                                                    
1808 +                mOverscrollEffectSet = false;                                                                     
1809 +                ((CellLayout) getChildAt(0)).setOverScrollAmount(0, false);                                       
1810 +                ((CellLayout) getChildAt(getChildCount() - 1)).setOverScrollAmount(0, false);                     
1811              }                                                                                                     
1812          }                                                                                                         
1813      }                                                                                                             
1814                                                                                                                    
1815      @Override                                                                                                     
1816      protected void overScroll(float amount) {                                                                     
1817 -        acceleratedOverScroll(amount);                                                                            
1818 +        boolean shouldOverScroll = (amount < 0 && (!hasCustomContent() || isLayoutRtl())) ||                      
1819 +                (amount > 0 && (!hasCustomContent() || !isLayoutRtl()));                                          
1820 +        if (shouldOverScroll) {                                                                                   
1821 +            dampedOverScroll(amount);                                                                             
1822 +            mOverScrollEffect = acceleratedOverFactor(amount);                                                    
1823 +        } else {                                                                                                  
1824 +            mOverScrollEffect = 0;                                                                                
1825 +        }                                                                                                         
1826      }                                                                                                             
1827                                                                                                                    
1828      protected void onAttachedToWindow() {                                                                         
1829          super.onAttachedToWindow();                                                                               
1830          mWindowToken = getWindowToken();                                                                          
1831          computeScroll();                                                                                          
1832          mDragController.setWindowToken(mWindowToken);                                                             
1833      }                                                                                                             
1834                                                                                                                    
1835      protected void onDetachedFromWindow() {                                                                       
1836          super.onDetachedFromWindow();                                                                             
1837          mWindowToken = null;                                                                                      
1838      }                                                                                                             
1839                                                                                                                    
1840      protected void onResume() {                                                                                   
1841          if (getPageIndicator() != null) {                                                                         
1842              // In case accessibility state has changed, we need to perform this on every                          
1843              // attach to window                                                                                   
1844              OnClickListener listener = getPageIndicatorClickListener();                                           
1845              if (listener != null) {                                                                               
1846                  getPageIndicator().setOnClickListener(listener);                                                  
1847              }                                                                                                     
1848          }                                                                                                         
1849          AccessibilityManager am = (AccessibilityManager)                                                          
1850                  getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);                                     
1851          sAccessibilityEnabled = am.isEnabled();                                                                   
1852                                                                                                                    
1853          // Update wallpaper dimensions if they were changed since last onResume                                   
1854          // (we also always set the wallpaper dimensions in the constructor)                                       
1855          if (LauncherAppState.getInstance().hasWallpaperChangedSinceLastCheck()) {                                 
1856              setWallpaperDimension();                                                                              
1857          }                                                                                                         
1858          mWallpaperIsLiveWallpaper = mWallpaperManager.getWallpaperInfo() != null;                                 
1859          // Force the wallpaper offset steps to be set again, because another app might have changed               
1860          // them                                                                                                   
1861          mLastSetWallpaperOffsetSteps = 0f;                                                                        
1862      }                                                                                                             
1863                                                                                                                    
1864      @Override                                                                                                     
1865      protected void onLayout(boolean changed, int left, int top, int right, int bottom) {                          
1866          if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) {                                
1867              mWallpaperOffset.syncWithScroll();                                                                    
1868              mWallpaperOffset.jumpToFinal();                                                                       
1869          }                                                                                                         
1870          super.onLayout(changed, left, top, right, bottom);                                                        
1871      }                                                                                                             
1872                                                                                                                    
1873      @Override                                                                                                     
1874      protected void onDraw(Canvas canvas) {                                                                        
1875 -        // Draw the background gradient if necessary                                                              
1876 -        if (mBackground != null && mBackgroundAlpha > 0.0f && mDrawBackground) {                                  
1877 -            int alpha = (int) (mBackgroundAlpha * 255);                                                           
1878 -            mBackground.setAlpha(alpha);                                                                          
1879 -            mBackground.setBounds(getScrollX(), 0, getScrollX() + getMeasuredWidth(),                             
1880 -                    getMeasuredHeight());                                                                         
1881 -            mBackground.draw(canvas);                                                                             
1882 -        }                                                                                                         
1883 -                                                                                                                  
1884          super.onDraw(canvas);                                                                                     
1885                                                                                                                    
1886          // Call back to LauncherModel to finish binding after the first draw                                      
1887          post(mBindPages);                                                                                         
1888 -    }                                                                                                             
1889 -                                                                                                                  
1890 -    boolean isDrawingBackgroundGradient() {                                                                       
1891 -        return (mBackground != null && mBackgroundAlpha > 0.0f && mDrawBackground);                               
1892      }                                                                                                             
1893                                                                                                                    
1894      @Override                                                                                                     
1895      protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {                    
1896          if (!mLauncher.isAllAppsVisible()) {                                                                      
1897              final Folder openFolder = getOpenFolder();                                                            
1898              if (openFolder != null) {                                                                             
1899                  return openFolder.requestFocus(direction, previouslyFocusedRect);                                 
1900              } else {                                                                                              
1901                  return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);                       
1902              }                                                                                                     
1903          }                                                                                                         
1904          return false;                                                                                             
1905      }                                                                                                             
1906                                                                                                                    
1907      @Override                                                                                                     
1908      public int getDescendantFocusability() {                                                                      
1909 -        if (isSmall()) {                                                                                          
1910 +        if (workspaceInModalState()) {                                                                            
1911              return ViewGroup.FOCUS_BLOCK_DESCENDANTS;                                                             
1912          }                                                                                                         
1913          return super.getDescendantFocusability();                                                                 
1914      }                                                                                                             
1915                                                                                                                    
1916      @Override                                                                                                     
1917      public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {                          
1918          if (!mLauncher.isAllAppsVisible()) {                                                                      
1919              final Folder openFolder = getOpenFolder();                                                            
1920              if (openFolder != null) {                                                                             
1921                  openFolder.addFocusables(views, direction);                                                       
1922              } else {                                                                                              
1923                  super.addFocusables(views, direction, focusableMode);                                             
1924              }                                                                                                     
1925          }                                                                                                         
1926      }                                                                                                             
1927                                                                                                                    
1928 -    public boolean isSmall() {                                                                                    
1929 -        return mState == State.SMALL || mState == State.SPRING_LOADED || mState == State.OVERVIEW;                
1930 +    public boolean workspaceInModalState() {                                                                      
1931 +        return mState != State.NORMAL;                                                                            
1932      }                                                                                                             
1933                                                                                                                    
1934      void enableChildrenCache(int fromPage, int toPage) {                                                          
1935          if (fromPage > toPage) {                                                                                  
1936              final int temp = fromPage;                                                                            
1937              fromPage = toPage;                                                                                    
1938              toPage = temp;                                                                                        
1939          }                                                                                                         
1940                                                                                                                    
1941          final int screenCount = getChildCount();                                                                  
1942                                                                                                                    
1943          fromPage = Math.max(fromPage, 0);                                                                         
1944          toPage = Math.min(toPage, screenCount - 1);                                                               
1945                                                                                                                    
1946          for (int i = fromPage; i <= toPage; i++) {                                                                
1947              final CellLayout layout = (CellLayout) getChildAt(i);                                                 
1948              layout.setChildrenDrawnWithCacheEnabled(true);                                                        
1949              layout.setChildrenDrawingCacheEnabled(true);                                                          
1950          }                                                                                                         
1951      }                                                                                                             
1952                                                                                                                    
1953      void clearChildrenCache() {                                                                                   
1954          final int screenCount = getChildCount();                                                                  
1955          for (int i = 0; i < screenCount; i++) {                                                                   
1956              final CellLayout layout = (CellLayout) getChildAt(i);                                                 
1957              layout.setChildrenDrawnWithCacheEnabled(false);                                                       
1958              // In software mode, we don't want the items to continue to be drawn into bitmaps                     
1959              if (!isHardwareAccelerated()) {                                                                       
1960                  layout.setChildrenDrawingCacheEnabled(false);                                                     
1961              }                                                                                                     
1962          }                                                                                                         
1963      }                                                                                                             
1964                                                                                                                    
1965      private void updateChildrenLayersEnabled(boolean force) {                                                     
1966 -        boolean small = mState == State.SMALL || mState == State.OVERVIEW || mIsSwitchingState;                   
1967 +        boolean small = mState == State.OVERVIEW || mIsSwitchingState;                                            
1968          boolean enableChildrenLayers = force || small || mAnimatingViewIntoPlace || isPageMoving();               
1969                                                                                                                    
1970          if (enableChildrenLayers != mChildrenLayersEnabled) {                                                     
1971              mChildrenLayersEnabled = enableChildrenLayers;                                                        
1972              if (mChildrenLayersEnabled) {                                                                         
1973                  enableHwLayersOnVisiblePages();                                                                   
1974              } else {                                                                                              
1975                  for (int i = 0; i < getPageCount(); i++) {                                                        
1976                      final CellLayout cl = (CellLayout) getChildAt(i);                                             
1977                      cl.enableHardwareLayer(false);                                                                
1978                  }                                                                                                 
1979              }                                                                                                     
1980          }                                                                                                         
1981      }                                                                                                             
1982                                                                                                                    
1983      private void enableHwLayersOnVisiblePages() {                                                                 
1984          if (mChildrenLayersEnabled) {                                                                             
1985              final int screenCount = getChildCount();                                                              
1986              getVisiblePages(mTempVisiblePagesRange);                                                              
1987              int leftScreen = mTempVisiblePagesRange[0];                                                           
1988              int rightScreen = mTempVisiblePagesRange[1];                                                          
1989              if (leftScreen == rightScreen) {                                                                      
1990                  // make sure we're caching at least two pages always                                              
1991                  if (rightScreen < screenCount - 1) {                                                              
1992                      rightScreen++;                                                                                
1993                  } else if (leftScreen > 0) {                                                                      
1994                      leftScreen--;                                                                                 
1995                  }                                                                                                 
1996              }                                                                                                     
1997                                                                                                                    
1998              final CellLayout customScreen = mWorkspaceScreens.get(CUSTOM_CONTENT_SCREEN_ID);                      
1999              for (int i = 0; i < screenCount; i++) {                                                               
2000                  final CellLayout layout = (CellLayout) getPageAt(i);                                              
2001                                                                                                                    
2002                  // enable layers between left and right screen inclusive, except for the                          
2003                  // customScreen, which may animate its content during transitions.                                
2004                  boolean enableLayer = layout != customScreen &&                                                   
2005                          leftScreen <= i && i <= rightScreen && shouldDrawChild(layout);                           
2006                  layout.enableHardwareLayer(enableLayer);                                                          
2007              }                                                                                                     
2008          }                                                                                                         
2009      }                                                                                                             
2010                                                                                                                    
2011      public void buildPageHardwareLayers() {                                                                       
2012          // force layers to be enabled just for the call to buildLayer                                             
2013          updateChildrenLayersEnabled(true);                                                                        
2014          if (getWindowToken() != null) {                                                                           
2015              final int childCount = getChildCount();                                                               
2016              for (int i = 0; i < childCount; i++) {                                                                
2017                  CellLayout cl = (CellLayout) getChildAt(i);                                                       
2018                  cl.buildHardwareLayer();                                                                          
2019              }                                                                                                     
2020          }                                                                                                         
2021          updateChildrenLayersEnabled(false);                                                                       
2022      }                                                                                                             
2023                                                                                                                    
2024      protected void onWallpaperTap(MotionEvent ev) {                                                               
2025          final int[] position = mTempCell;                                                                         
2026          getLocationOnScreen(position);                                                                            
2027                                                                                                                    
2028          int pointerIndex = ev.getActionIndex();                                                                   
2029          position[0] += (int) ev.getX(pointerIndex);                                                               
2030          position[1] += (int) ev.getY(pointerIndex);                                                               
2031                                                                                                                    
2032          mWallpaperManager.sendWallpaperCommand(getWindowToken(),                                                  
2033                  ev.getAction() == MotionEvent.ACTION_UP                                                           
2034                          ? WallpaperManager.COMMAND_TAP : WallpaperManager.COMMAND_SECONDARY_TAP,                  
2035                  position[0], position[1], 0, null);                                                               
2036      }                                                                                                             
2037                                                                                                                    
2038      /*                                                                                                            
2039       * This interpolator emulates the rate at which the perceived scale of an object changes                      
2040       * as its distance from a camera increases. When this interpolator is applied to a scale                      
2041       * animation on a view, it evokes the sense that the object is shrinking due to moving away                   
2042       * from the camera.                                                                                           
2043       */                                                                                                           
2044      static class ZInterpolator implements TimeInterpolator {                                                      
2045          private float focalLength;                                                                                
2046                                                                                                                    
2047          public ZInterpolator(float foc) {                                                                         
2048              focalLength = foc;                                                                                    
2049          }                                                                                                         
2050                                                                                                                    
2051          public float getInterpolation(float input) {                                                              
2052              return (1.0f - focalLength / (focalLength + input)) /                                                 
2053                  (1.0f - focalLength / (focalLength + 1.0f));                                                      
2054          }                                                                                                         
2055      }                                                                                                             
2056                                                                                                                    
2057      /*                                                                                                            
2058       * The exact reverse of ZInterpolator.                                                                        
2059       */                                                                                                           
2060      static class InverseZInterpolator implements TimeInterpolator {                                               
2061          private ZInterpolator zInterpolator;                                                                      
2062          public InverseZInterpolator(float foc) {                                                                  
2063              zInterpolator = new ZInterpolator(foc);                                                               
2064          }                                                                                                         
2065          public float getInterpolation(float input) {                                                              
2066              return 1 - zInterpolator.getInterpolation(1 - input);                                                 
2067          }                                                                                                         
2068      }                                                                                                             
2069                                                                                                                    
2070      /*                                                                                                            
2071       * ZInterpolator compounded with an ease-out.                                                                 
2072       */                                                                                                           
2073      static class ZoomOutInterpolator implements TimeInterpolator {                                                
2074          private final DecelerateInterpolator decelerate = new DecelerateInterpolator(0.75f);                      
2075          private final ZInterpolator zInterpolator = new ZInterpolator(0.13f);                                     
2076                                                                                                                    
2077          public float getInterpolation(float input) {                                                              
2078              return decelerate.getInterpolation(zInterpolator.getInterpolation(input));                            
2079          }                                                                                                         
2080      }                                                                                                             
2081                                                                                                                    
2082      /*                                                                                                            
2083       * InvereZInterpolator compounded with an ease-out.                                                           
2084       */                                                                                                           
2085      static class ZoomInInterpolator implements TimeInterpolator {                                                 
2086          private final InverseZInterpolator inverseZInterpolator = new InverseZInterpolator(0.35f);                
2087          private final DecelerateInterpolator decelerate = new DecelerateInterpolator(3.0f);                       
2088                                                                                                                    
2089          public float getInterpolation(float input) {                                                              
2090              return decelerate.getInterpolation(inverseZInterpolator.getInterpolation(input));                     
2091          }                                                                                                         
2092      }                                                                                                             
2093                                                                                                                    
2094      private final ZoomInInterpolator mZoomInInterpolator = new ZoomInInterpolator();                              
2095                                                                                                                    
2096      /*                                                                                                            
2097      *                                                                                                             
2098      * We call these methods (onDragStartedWithItemSpans/onDragStartedWithSize) whenever we                        
2099      * start a drag in Launcher, regardless of whether the drag has ever entered the Workspace                     
2100      *                                                                                                             
2101      * These methods mark the appropriate pages as accepting drops (which alters their visual                      
2102      * appearance).                                                                                                
2103      *                                                                                                             
2104      */                                                                                                            
2105 -    public void onDragStartedWithItem(View v) {                                                                   
2106 -        final Canvas canvas = new Canvas();                                                                       
2107 +    private static Rect getDrawableBounds(Drawable d) {                                                           
2108 +        Rect bounds = new Rect();                                                                                 
2109 +        d.copyBounds(bounds);                                                                                     
2110 +        if (bounds.width() == 0 || bounds.height() == 0) {                                                        
2111 +            bounds.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());                                      
2112 +        } else {                                                                                                  
2113 +            bounds.offsetTo(0, 0);                                                                                
2114 +        }                                                                                                         
2115 +        if (d instanceof PreloadIconDrawable) {                                                                   
2116 +            int inset = -((PreloadIconDrawable) d).getOutset();                                                   
2117 +            bounds.inset(inset, inset);                                                                           
2118 +        }                                                                                                         
2119 +        return bounds;                                                                                            
2120 +    }                                                                                                             
2121 +                                                                                                                  
2122 +    public void onExternalDragStartedWithItem(View v) {                                                           
2123 +        // Compose a drag bitmap with the view scaled to the icon size                                            
2124 +        LauncherAppState app = LauncherAppState.getInstance();                                                    
2125 +        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                             
2126 +        int iconSize = grid.iconSizePx;                                                                           
2127 +        int bmpWidth = v.getMeasuredWidth();                                                                      
2128 +        int bmpHeight = v.getMeasuredHeight();                                                                    
2129 +                                                                                                                  
2130 +        // If this is a text view, use its drawable instead                                                       
2131 +        if (v instanceof TextView) {                                                                              
2132 +            TextView tv = (TextView) v;                                                                           
2133 +            Drawable d = tv.getCompoundDrawables()[1];                                                            
2134 +            Rect bounds = getDrawableBounds(d);                                                                   
2135 +            bmpWidth = bounds.width();                                                                            
2136 +            bmpHeight = bounds.height();                                                                          
2137 +        }                                                                                                         
2138 +                                                                                                                  
2139 +        // Compose the bitmap to create the icon from                                                             
2140 +        Bitmap b = Bitmap.createBitmap(bmpWidth, bmpHeight,                                                       
2141 +                Bitmap.Config.ARGB_8888);                                                                         
2142 +        mCanvas.setBitmap(b);                                                                                     
2143 +        drawDragView(v, mCanvas, 0);                                                                              
2144 +        mCanvas.setBitmap(null);                                                                                  
2145                                                                                                                    
2146          // The outline is used to visualize where the item will land if dropped                                   
2147 -        mDragOutline = createDragOutline(v, canvas, DRAG_BITMAP_PADDING);                                         
2148 +        mDragOutline = createDragOutline(b, DRAG_BITMAP_PADDING, iconSize, iconSize, true);                       
2149      }                                                                                                             
2150                                                                                                                    
2151      public void onDragStartedWithItem(PendingAddItemInfo info, Bitmap b, boolean clipAlpha) {                     
2152 -        final Canvas canvas = new Canvas();                                                                       
2153 -                                                                                                                  
2154          int[] size = estimateItemSize(info.spanX, info.spanY, info, false);                                       
2155                                                                                                                    
2156          // The outline is used to visualize where the item will land if dropped                                   
2157 -        mDragOutline = createDragOutline(b, canvas, DRAG_BITMAP_PADDING, size[0],                                 
2158 -                size[1], clipAlpha);                                                                              
2159 +        mDragOutline = createDragOutline(b, DRAG_BITMAP_PADDING, size[0], size[1], clipAlpha);                    
2160      }                                                                                                             
2161                                                                                                                    
2162      public void exitWidgetResizeMode() {                                                                          
2163          DragLayer dragLayer = mLauncher.getDragLayer();                                                           
2164          dragLayer.clearAllResizeFrames();                                                                         
2165      }                                                                                                             
2166                                                                                                                    
2167      private void initAnimationArrays() {                                                                          
2168          final int childCount = getChildCount();                                                                   
2169          if (mLastChildCount == childCount) return;                                                                
2170                                                                                                                    
2171          mOldBackgroundAlphas = new float[childCount];                                                             
2172          mOldAlphas = new float[childCount];                                                                       
2173          mNewBackgroundAlphas = new float[childCount];                                                             
2174          mNewAlphas = new float[childCount];                                                                       
2175      }                                                                                                             
2176                                                                                                                    
2177 -    Animator getChangeStateAnimation(final State state, boolean animated) {                                       
2178 -        return getChangeStateAnimation(state, animated, 0, -1);                                                   
2179 +    Animator getChangeStateAnimation(final State state, boolean animated,                                         
2180 +            ArrayList<View> layerViews) {                                                                         
2181 +        return getChangeStateAnimation(state, animated, 0, -1, layerViews);                                       
2182      }                                                                                                             
2183                                                                                                                    
2184      @Override                                                                                                     
2185 -    protected void getOverviewModePages(int[] range) {                                                            
2186 +    protected void getFreeScrollPageRange(int[] range) {                                                          
2187 +        getOverviewModePages(range);                                                                              
2188 +    }                                                                                                             
2189 +                                                                                                                  
2190 +    private void getOverviewModePages(int[] range) {                                                              
2191          int start = numCustomPages();                                                                             
2192          int end = getChildCount() - 1;                                                                            
2193                                                                                                                    
2194          range[0] = Math.max(0, Math.min(start, getChildCount() - 1));                                             
2195          range[1] = Math.max(0,  end);                                                                             
2196 -     }                                                                                                            
2197 +    }                                                                                                             
2198                                                                                                                    
2199      protected void onStartReordering() {                                                                          
2200          super.onStartReordering();                                                                                
2201          showOutlines();                                                                                           
2202          // Reordering handles its own animations, disable the automatic ones.                                     
2203          disableLayoutTransitions();                                                                               
2204      }                                                                                                             
2205                                                                                                                    
2206      protected void onEndReordering() {                                                                            
2207          super.onEndReordering();                                                                                  
2208 +                                                                                                                  
2209 +        if (mLauncher.isWorkspaceLoading()) {                                                                     
2210 +            // Invalid and dangerous operation if workspace is loading                                            
2211 +            return;                                                                                               
2212 +        }                                                                                                         
2213                                                                                                                    
2214          hideOutlines();                                                                                           
2215          mScreenOrder.clear();                                                                                     
2216          int count = getChildCount();                                                                              
2217          for (int i = 0; i < count; i++) {                                                                         
2218              CellLayout cl = ((CellLayout) getChildAt(i));                                                         
2219              mScreenOrder.add(getIdForScreen(cl));                                                                 
2220          }                                                                                                         
2221                                                                                                                    
2222          mLauncher.getModel().updateWorkspaceScreenOrder(mLauncher, mScreenOrder);                                 
2223                                                                                                                    
2224          // Re-enable auto layout transitions for page deletion.                                                   
2225          enableLayoutTransitions();                                                                                
2226      }                                                                                                             
2227                                                                                                                    
2228      public boolean isInOverviewMode() {                                                                           
2229          return mState == State.OVERVIEW;                                                                          
2230      }                                                                                                             
2231                                                                                                                    
2232      public boolean enterOverviewMode() {                                                                          
2233          if (mTouchState != TOUCH_STATE_REST) {                                                                    
2234              return false;                                                                                         
2235          }                                                                                                         
2236          enableOverviewMode(true, -1, true);                                                                       
2237          return true;                                                                                              
2238      }                                                                                                             
2239                                                                                                                    
2240      public void exitOverviewMode(boolean animated) {                                                              
2241          exitOverviewMode(-1, animated);                                                                           
2242      }                                                                                                             
2243                                                                                                                    
2244      public void exitOverviewMode(int snapPage, boolean animated) {                                                
2245          enableOverviewMode(false, snapPage, animated);                                                            
2246      }                                                                                                             
2247                                                                                                                    
2248      private void enableOverviewMode(boolean enable, int snapPage, boolean animated) {                             
2249          State finalState = Workspace.State.OVERVIEW;                                                              
2250          if (!enable) {                                                                                            
2251              finalState = Workspace.State.NORMAL;                                                                  
2252          }                                                                                                         
2253                                                                                                                    
2254          Animator workspaceAnim = getChangeStateAnimation(finalState, animated, 0, snapPage);                      
2255          if (workspaceAnim != null) {                                                                              
2256              onTransitionPrepare();                                                                                
2257              workspaceAnim.addListener(new AnimatorListenerAdapter() {                                             
2258                  @Override                                                                                         
2259                  public void onAnimationEnd(Animator arg0) {                                                       
2260                      onTransitionEnd();                                                                            
2261                  }                                                                                                 
2262              });                                                                                                   
2263              workspaceAnim.start();                                                                                
2264          }                                                                                                         
2265      }                                                                                                             
2266                                                                                                                    
2267      int getOverviewModeTranslationY() {                                                                           
2268          LauncherAppState app = LauncherAppState.getInstance();                                                    
2269          DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                             
2270          Rect overviewBar = grid.getOverviewModeButtonBarRect();                                                   
2271                                                                                                                    
2272          int availableHeight = getViewportHeight();                                                                
2273          int scaledHeight = (int) (mOverviewModeShrinkFactor * getNormalChildHeight());                            
2274          int offsetFromTopEdge = (availableHeight - scaledHeight) / 2;                                             
2275          int offsetToCenterInOverview = (availableHeight - mInsets.top - overviewBar.height()                      
2276                  - scaledHeight) / 2;                                                                              
2277                                                                                                                    
2278          return -offsetFromTopEdge + mInsets.top + offsetToCenterInOverview;                                       
2279      }                                                                                                             
2280                                                                                                                    
2281      boolean shouldVoiceButtonProxyBeVisible() {                                                                   
2282          if (isOnOrMovingToCustomContent()) {                                                                      
2283              return false;                                                                                         
2284          }                                                                                                         
2285          if (mState != State.NORMAL) {                                                                             
2286              return false;                                                                                         
2287          }                                                                                                         
2288          return true;                                                                                              
2289      }                                                                                                             
2290                                                                                                                    
2291      public void updateInteractionForState() {                                                                     
2292          if (mState != State.NORMAL) {                                                                             
2293              mLauncher.onInteractionBegin();                                                                       
2294          } else {                                                                                                  
2295              mLauncher.onInteractionEnd();                                                                         
2296          }                                                                                                         
2297      }                                                                                                             
2298                                                                                                                    
2299      private void setState(State state) {                                                                          
2300          mState = state;                                                                                           
2301          updateInteractionForState();                                                                              
2302          updateAccessibilityFlags();                                                                               
2303      }                                                                                                             
2304                                                                                                                    
2305 +    State getState() {                                                                                            
2306 +        return mState;                                                                                            
2307 +    }                                                                                                             
2308 +                                                                                                                  
2309      private void updateAccessibilityFlags() {                                                                     
2310          int accessible = mState == State.NORMAL ?                                                                 
2311                  ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES :                                                      
2312                  ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS;                                       
2313          setImportantForAccessibility(accessible);                                                                 
2314      }                                                                                                             
2315                                                                                                                    
2316 +    private static final int HIDE_WORKSPACE_DURATION = 100;                                                       
2317 +                                                                                                                  
2318      Animator getChangeStateAnimation(final State state, boolean animated, int delay, int snapPage) {              
2319 +        return getChangeStateAnimation(state, animated, delay, snapPage, null);                                   
2320 +    }                                                                                                             
2321 +                                                                                                                  
2322 +    Animator getChangeStateAnimation(final State state, boolean animated, int delay, int snapPage,                
2323 +            ArrayList<View> layerViews) {                                                                         
2324          if (mState == state) {                                                                                    
2325              return null;                                                                                          
2326          }                                                                                                         
2327                                                                                                                    
2328          // Initialize animation arrays for the first time if necessary                                            
2329          initAnimationArrays();                                                                                    
2330                                                                                                                    
2331          AnimatorSet anim = animated ? LauncherAnimUtils.createAnimatorSet() : null;                               
2332                                                                                                                    
2333          final State oldState = mState;                                                                            
2334          final boolean oldStateIsNormal = (oldState == State.NORMAL);                                              
2335          final boolean oldStateIsSpringLoaded = (oldState == State.SPRING_LOADED);                                 
2336 -        final boolean oldStateIsSmall = (oldState == State.SMALL);                                                
2337 +        final boolean oldStateIsNormalHidden = (oldState == State.NORMAL_HIDDEN);                                 
2338 +        final boolean oldStateIsOverviewHidden = (oldState == State.OVERVIEW_HIDDEN);                             
2339          final boolean oldStateIsOverview = (oldState == State.OVERVIEW);                                          
2340          setState(state);                                                                                          
2341          final boolean stateIsNormal = (state == State.NORMAL);                                                    
2342          final boolean stateIsSpringLoaded = (state == State.SPRING_LOADED);                                       
2343 -        final boolean stateIsSmall = (state == State.SMALL);                                                      
2344 +        final boolean stateIsNormalHidden = (state == State.NORMAL_HIDDEN);                                       
2345 +        final boolean stateIsOverviewHidden = (state == State.OVERVIEW_HIDDEN);                                   
2346          final boolean stateIsOverview = (state == State.OVERVIEW);                                                
2347          float finalBackgroundAlpha = (stateIsSpringLoaded || stateIsOverview) ? 1.0f : 0f;                        
2348 -        float finalHotseatAndPageIndicatorAlpha = (stateIsOverview || stateIsSmall) ? 0f : 1f;                    
2349 +        float finalHotseatAndPageIndicatorAlpha = (stateIsNormal || stateIsSpringLoaded) ? 1f : 0f;               
2350          float finalOverviewPanelAlpha = stateIsOverview ? 1f : 0f;                                                
2351          float finalSearchBarAlpha = !stateIsNormal ? 0f : 1f;                                                     
2352 -        float finalWorkspaceTranslationY = stateIsOverview ? getOverviewModeTranslationY() : 0;                   
2353 -                                                                                                                  
2354 -        boolean workspaceToAllApps = (oldStateIsNormal && stateIsSmall);                                          
2355 -        boolean allAppsToWorkspace = (oldStateIsSmall && stateIsNormal);                                          
2356 +        float finalWorkspaceTranslationY = stateIsOverview || stateIsOverviewHidden ?                             
2357 +                getOverviewModeTranslationY() : 0;                                                                
2358 +                                                                                                                  
2359 +        boolean workspaceToAllApps = (oldStateIsNormal && stateIsNormalHidden);                                   
2360 +        boolean overviewToAllApps = (oldStateIsOverview && stateIsOverviewHidden);                                
2361 +        boolean allAppsToWorkspace = (stateIsNormalHidden && stateIsNormal);                                      
2362          boolean workspaceToOverview = (oldStateIsNormal && stateIsOverview);                                      
2363          boolean overviewToWorkspace = (oldStateIsOverview && stateIsNormal);                                      
2364                                                                                                                    
2365          mNewScale = 1.0f;                                                                                         
2366                                                                                                                    
2367          if (oldStateIsOverview) {                                                                                 
2368              disableFreeScroll();                                                                                  
2369          } else if (stateIsOverview) {                                                                             
2370              enableFreeScroll();                                                                                   
2371          }                                                                                                         
2372                                                                                                                    
2373          if (state != State.NORMAL) {                                                                              
2374              if (stateIsSpringLoaded) {                                                                            
2375                  mNewScale = mSpringLoadedShrinkFactor;                                                            
2376 -            } else if (stateIsOverview) {                                                                         
2377 +            } else if (stateIsOverview || stateIsOverviewHidden) {                                                
2378                  mNewScale = mOverviewModeShrinkFactor;                                                            
2379 -            } else if (stateIsSmall){                                                                             
2380 -                mNewScale = mOverviewModeShrinkFactor - 0.3f;                                                     
2381 -            }                                                                                                     
2382 -            if (workspaceToAllApps) {                                                                             
2383 -                updateChildrenLayersEnabled(false);                                                               
2384              }                                                                                                     
2385          }                                                                                                         
2386                                                                                                                    
2387          final int duration;                                                                                       
2388 -        if (workspaceToAllApps) {                                                                                 
2389 -            duration = getResources().getInteger(R.integer.config_workspaceUnshrinkTime);                         
2390 +        if (workspaceToAllApps || overviewToAllApps) {                                                            
2391 +            duration = HIDE_WORKSPACE_DURATION; //getResources().getInteger(R.integer.config_workspaceUnshrinkTime🔵
2392          } else if (workspaceToOverview || overviewToWorkspace) {                                                  
2393              duration = getResources().getInteger(R.integer.config_overviewTransitionTime);                        
2394          } else {                                                                                                  
2395              duration = getResources().getInteger(R.integer.config_appsCustomizeWorkspaceShrinkTime);              
2396          }                                                                                                         
2397                                                                                                                    
2398          if (snapPage == -1) {                                                                                     
2399              snapPage = getPageNearestToCenterOfScreen();                                                          
2400          }                                                                                                         
2401          snapToPage(snapPage, duration, mZoomInInterpolator);                                                      
2402                                                                                                                    
2403          for (int i = 0; i < getChildCount(); i++) {                                                               
2404              final CellLayout cl = (CellLayout) getChildAt(i);                                                     
2405              boolean isCurrentPage = (i == snapPage);                                                              
2406              float initialAlpha = cl.getShortcutsAndWidgets().getAlpha();                                          
2407              float finalAlpha;                                                                                     
2408 -            if (stateIsSmall) {                                                                                   
2409 +            if (stateIsNormalHidden || stateIsOverviewHidden) {                                                   
2410                  finalAlpha = 0f;                                                                                  
2411              } else if (stateIsNormal && mWorkspaceFadeInAdjacentScreens) {                                        
2412                  finalAlpha = (i == snapPage || i < numCustomPages()) ? 1f : 0f;                                   
2413              } else {                                                                                              
2414                  finalAlpha = 1f;                                                                                  
2415              }                                                                                                     
2416                                                                                                                    
2417              // If we are animating to/from the small state, then hide the side pages and fade the                 
2418              // current page in                                                                                    
2419              if (!mIsSwitchingState) {                                                                             
2420                  if (workspaceToAllApps || allAppsToWorkspace) {                                                   
2421                      if (allAppsToWorkspace && isCurrentPage) {                                                    
2422                          initialAlpha = 0f;                                                                        
2423                      } else if (!isCurrentPage) {                                                                  
2424                          initialAlpha = finalAlpha = 0f;                                                           
2425                      }                                                                                             
2426                      cl.setShortcutAndWidgetAlpha(initialAlpha);                                                   
2427                  }                                                                                                 
2428              }                                                                                                     
2429                                                                                                                    
2430              mOldAlphas[i] = initialAlpha;                                                                         
2431              mNewAlphas[i] = finalAlpha;                                                                           
2432              if (animated) {                                                                                       
2433                  mOldBackgroundAlphas[i] = cl.getBackgroundAlpha();                                                
2434                  mNewBackgroundAlphas[i] = finalBackgroundAlpha;                                                   
2435              } else {                                                                                              
2436                  cl.setBackgroundAlpha(finalBackgroundAlpha);                                                      
2437                  cl.setShortcutAndWidgetAlpha(finalAlpha);                                                         
2438              }                                                                                                     
2439          }                                                                                                         
2440                                                                                                                    
2441          final View searchBar = mLauncher.getQsbBar();                                                             
2442          final View overviewPanel = mLauncher.getOverviewPanel();                                                  
2443          final View hotseat = mLauncher.getHotseat();                                                              
2444          final View pageIndicator = getPageIndicator();                                                            
2445          if (animated) {                                                                                           
2446 -            anim.setDuration(duration);                                                                           
2447              LauncherViewPropertyAnimator scale = new LauncherViewPropertyAnimator(this);                          
2448              scale.scaleX(mNewScale)                                                                               
2449                  .scaleY(mNewScale)                                                                                
2450                  .translationY(finalWorkspaceTranslationY)                                                         
2451 +                .setDuration(duration)                                                                            
2452                  .setInterpolator(mZoomInInterpolator);                                                            
2453              anim.play(scale);                                                                                     
2454              for (int index = 0; index < getChildCount(); index++) {                                               
2455                  final int i = index;                                                                              
2456                  final CellLayout cl = (CellLayout) getChildAt(i);                                                 
2457                  float currentAlpha = cl.getShortcutsAndWidgets().getAlpha();                                      
2458                  if (mOldAlphas[i] == 0 && mNewAlphas[i] == 0) {                                                   
2459                      cl.setBackgroundAlpha(mNewBackgroundAlphas[i]);                                               
2460                      cl.setShortcutAndWidgetAlpha(mNewAlphas[i]);                                                  
2461                  } else {                                                                                          
2462 +                    if (layerViews != null) {                                                                     
2463 +                        layerViews.add(cl);                                                                       
2464 +                    }                                                                                             
2465                      if (mOldAlphas[i] != mNewAlphas[i] || currentAlpha != mNewAlphas[i]) {                        
2466                          LauncherViewPropertyAnimator alphaAnim =                                                  
2467                              new LauncherViewPropertyAnimator(cl.getShortcutsAndWidgets());                        
2468                          alphaAnim.alpha(mNewAlphas[i])                                                            
2469 +                            .setDuration(duration)                                                                
2470                              .setInterpolator(mZoomInInterpolator);                                                
2471                          anim.play(alphaAnim);                                                                     
2472                      }                                                                                             
2473                      if (mOldBackgroundAlphas[i] != 0 ||                                                           
2474                          mNewBackgroundAlphas[i] != 0) {                                                           
2475                          ValueAnimator bgAnim =                                                                    
2476                                  LauncherAnimUtils.ofFloat(cl, 0f, 1f);                                            
2477                          bgAnim.setInterpolator(mZoomInInterpolator);                                              
2478 +                        bgAnim.setDuration(duration);                                                             
2479                          bgAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {                           
2480                                  public void onAnimationUpdate(float a, float b) {                                 
2481                                      cl.setBackgroundAlpha(                                                        
2482                                              a * mOldBackgroundAlphas[i] +                                         
2483                                              b * mNewBackgroundAlphas[i]);                                         
2484                                  }                                                                                 
2485                              });                                                                                   
2486                          anim.play(bgAnim);                                                                        
2487                      }                                                                                             
2488                  }                                                                                                 
2489              }                                                                                                     
2490              Animator pageIndicatorAlpha = null;                                                                   
2491              if (pageIndicator != null) {                                                                          
2492                  pageIndicatorAlpha = new LauncherViewPropertyAnimator(pageIndicator)                              
2493                      .alpha(finalHotseatAndPageIndicatorAlpha).withLayer();                                        
2494                  pageIndicatorAlpha.addListener(new AlphaUpdateListener(pageIndicator));                           
2495              } else {                                                                                              
2496                  // create a dummy animation so we don't need to do null checks later                              
2497                  pageIndicatorAlpha = ValueAnimator.ofFloat(0, 0);                                                 
2498              }                                                                                                     
2499                                                                                                                    
2500              Animator hotseatAlpha = new LauncherViewPropertyAnimator(hotseat)                                     
2501                  .alpha(finalHotseatAndPageIndicatorAlpha).withLayer();                                            
2502              hotseatAlpha.addListener(new AlphaUpdateListener(hotseat));                                           
2503                                                                                                                    
2504              Animator searchBarAlpha = new LauncherViewPropertyAnimator(searchBar)                                 
2505                  .alpha(finalSearchBarAlpha).withLayer();                                                          
2506              searchBarAlpha.addListener(new AlphaUpdateListener(searchBar));                                       
2507                                                                                                                    
2508              Animator overviewPanelAlpha = new LauncherViewPropertyAnimator(overviewPanel)                         
2509                  .alpha(finalOverviewPanelAlpha).withLayer();                                                      
2510              overviewPanelAlpha.addListener(new AlphaUpdateListener(overviewPanel));                               
2511                                                                                                                    
2512 +            // For animation optimations, we may need to provide the Launcher transition                          
2513 +            // with a set of views on which to force build layers in certain scenarios.                           
2514 +            hotseat.setLayerType(View.LAYER_TYPE_HARDWARE, null);                                                 
2515 +            searchBar.setLayerType(View.LAYER_TYPE_HARDWARE, null);                                               
2516 +            overviewPanel.setLayerType(View.LAYER_TYPE_HARDWARE, null);                                           
2517 +            if (layerViews != null) {                                                                             
2518 +                layerViews.add(hotseat);                                                                          
2519 +                layerViews.add(searchBar);                                                                        
2520 +                layerViews.add(overviewPanel);                                                                    
2521 +            }                                                                                                     
2522 +                                                                                                                  
2523              if (workspaceToOverview) {                                                                            
2524                  pageIndicatorAlpha.setInterpolator(new DecelerateInterpolator(2));                                
2525                  hotseatAlpha.setInterpolator(new DecelerateInterpolator(2));                                      
2526                  overviewPanelAlpha.setInterpolator(null);                                                         
2527              } else if (overviewToWorkspace) {                                                                     
2528                  pageIndicatorAlpha.setInterpolator(null);                                                         
2529                  hotseatAlpha.setInterpolator(null);                                                               
2530                  overviewPanelAlpha.setInterpolator(new DecelerateInterpolator(2));                                
2531              }                                                                                                     
2532 -            searchBarAlpha.setInterpolator(null);                                                                 
2533 +                                                                                                                  
2534 +            overviewPanelAlpha.setDuration(duration);                                                             
2535 +            pageIndicatorAlpha.setDuration(duration);                                                             
2536 +            hotseatAlpha.setDuration(duration);                                                                   
2537 +            searchBarAlpha.setDuration(duration);                                                                 
2538                                                                                                                    
2539              anim.play(overviewPanelAlpha);                                                                        
2540              anim.play(hotseatAlpha);                                                                              
2541              anim.play(searchBarAlpha);                                                                            
2542              anim.play(pageIndicatorAlpha);                                                                        
2543              anim.setStartDelay(delay);                                                                            
2544          } else {                                                                                                  
2545              overviewPanel.setAlpha(finalOverviewPanelAlpha);                                                      
2546              AlphaUpdateListener.updateVisibility(overviewPanel);                                                  
2547              hotseat.setAlpha(finalHotseatAndPageIndicatorAlpha);                                                  
2548              AlphaUpdateListener.updateVisibility(hotseat);                                                        
2549              if (pageIndicator != null) {                                                                          
2550                  pageIndicator.setAlpha(finalHotseatAndPageIndicatorAlpha);                                        
2551                  AlphaUpdateListener.updateVisibility(pageIndicator);                                              
2552              }                                                                                                     
2553              searchBar.setAlpha(finalSearchBarAlpha);                                                              
2554              AlphaUpdateListener.updateVisibility(searchBar);                                                      
2555              updateCustomContentVisibility();                                                                      
2556              setScaleX(mNewScale);                                                                                 
2557              setScaleY(mNewScale);                                                                                 
2558              setTranslationY(finalWorkspaceTranslationY);                                                          
2559          }                                                                                                         
2560          mLauncher.updateVoiceButtonProxyVisible(false);                                                           
2561                                                                                                                    
2562 -        if (stateIsSpringLoaded) {                                                                                
2563 -            // Right now we're covered by Apps Customize                                                          
2564 -            // Show the background gradient immediately, so the gradient will                                     
2565 -            // be showing once AppsCustomize disappears                                                           
2566 +        if (stateIsNormal) {                                                                                      
2567 +            animateBackgroundGradient(0f, animated);                                                              
2568 +        } else {                                                                                                  
2569              animateBackgroundGradient(getResources().getInteger(                                                  
2570 -                    R.integer.config_appsCustomizeSpringLoadedBgAlpha) / 100f, false);                            
2571 -        } else if (stateIsOverview) {                                                                             
2572 -            animateBackgroundGradient(getResources().getInteger(                                                  
2573 -                    R.integer.config_appsCustomizeSpringLoadedBgAlpha) / 100f, true);                             
2574 -        } else {                                                                                                  
2575 -            // Fade the background gradient away                                                                  
2576 -            animateBackgroundGradient(0f, animated);                                                              
2577 +                    R.integer.config_workspaceScrimAlpha) / 100f, animated);                                      
2578          }                                                                                                         
2579          return anim;                                                                                              
2580      }                                                                                                             
2581                                                                                                                    
2582      static class AlphaUpdateListener implements AnimatorUpdateListener, AnimatorListener {                        
2583          View view;                                                                                                
2584          public AlphaUpdateListener(View v) {                                                                      
2585              view = v;                                                                                             
2586          }                                                                                                         
2587                                                                                                                    
2588          @Override                                                                                                 
2589          public void onAnimationUpdate(ValueAnimator arg0) {                                                       
2590              updateVisibility(view);                                                                               
2591          }                                                                                                         
2592                                                                                                                    
2593          public static void updateVisibility(View view) {                                                          
2594              // We want to avoid the extra layout pass by setting the views to GONE unless                         
2595              // accessibility is on, in which case not setting them to GONE causes a glitch.                       
2596              int invisibleState = sAccessibilityEnabled ? GONE : INVISIBLE;                                        
2597              if (view.getAlpha() < ALPHA_CUTOFF_THRESHOLD && view.getVisibility() != invisibleState) {             
2598                  view.setVisibility(invisibleState);                                                               
2599              } else if (view.getAlpha() > ALPHA_CUTOFF_THRESHOLD                                                   
2600                      && view.getVisibility() != VISIBLE) {                                                         
2601                  view.setVisibility(VISIBLE);                                                                      
2602              }                                                                                                     
2603          }                                                                                                         
2604                                                                                                                    
2605          @Override                                                                                                 
2606          public void onAnimationCancel(Animator arg0) {                                                            
2607          }                                                                                                         
2608                                                                                                                    
2609          @Override                                                                                                 
2610          public void onAnimationEnd(Animator arg0) {                                                               
2611              updateVisibility(view);                                                                               
2612          }                                                                                                         
2613                                                                                                                    
2614          @Override                                                                                                 
2615          public void onAnimationRepeat(Animator arg0) {                                                            
2616          }                                                                                                         
2617                                                                                                                    
2618          @Override                                                                                                 
2619          public void onAnimationStart(Animator arg0) {                                                             
2620              // We want the views to be visible for animation, so fade-in/out is visible                           
2621              view.setVisibility(VISIBLE);                                                                          
2622          }                                                                                                         
2623      }                                                                                                             
2624                                                                                                                    
2625      @Override                                                                                                     
2626      public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) {                  
2627          onTransitionPrepare();                                                                                    
2628      }                                                                                                             
2629                                                                                                                    
2630      @Override                                                                                                     
2631      public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) {                    
2632      }                                                                                                             
2633                                                                                                                    
2634      @Override                                                                                                     
2635      public void onLauncherTransitionStep(Launcher l, float t) {                                                   
2636          mTransitionProgress = t;                                                                                  
2637      }                                                                                                             
2638                                                                                                                    
2639      @Override                                                                                                     
2640      public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {                      
2641          onTransitionEnd();                                                                                        
2642      }                                                                                                             
2643                                                                                                                    
2644      private void onTransitionPrepare() {                                                                          
2645          mIsSwitchingState = true;                                                                                 
2646                                                                                                                    
2647          // Invalidate here to ensure that the pages are rendered during the state change transition.              
2648          invalidate();                                                                                             
2649                                                                                                                    
2650          updateChildrenLayersEnabled(false);                                                                       
2651          hideCustomContentIfNecessary();                                                                           
2652      }                                                                                                             
2653                                                                                                                    
2654      void updateCustomContentVisibility() {                                                                        
2655          int visibility = mState == Workspace.State.NORMAL ? VISIBLE : INVISIBLE;                                  
2656          if (hasCustomContent()) {                                                                                 
2657              mWorkspaceScreens.get(CUSTOM_CONTENT_SCREEN_ID).setVisibility(visibility);                            
2658          }                                                                                                         
2659      }                                                                                                             
2660                                                                                                                    
2661      void showCustomContentIfNecessary() {                                                                         
2662          boolean show  = mState == Workspace.State.NORMAL;                                                         
2663          if (show && hasCustomContent()) {                                                                         
2664              mWorkspaceScreens.get(CUSTOM_CONTENT_SCREEN_ID).setVisibility(VISIBLE);                               
2665          }                                                                                                         
2666      }                                                                                                             
2667                                                                                                                    
2668      void hideCustomContentIfNecessary() {                                                                         
2669          boolean hide  = mState != Workspace.State.NORMAL;                                                         
2670          if (hide && hasCustomContent()) {                                                                         
2671              disableLayoutTransitions();                                                                           
2672              mWorkspaceScreens.get(CUSTOM_CONTENT_SCREEN_ID).setVisibility(INVISIBLE);                             
2673              enableLayoutTransitions();                                                                            
2674          }                                                                                                         
2675      }                                                                                                             
2676                                                                                                                    
2677      private void onTransitionEnd() {                                                                              
2678          mIsSwitchingState = false;                                                                                
2679          updateChildrenLayersEnabled(false);                                                                       
2680 -        // The code in getChangeStateAnimation to determine initialAlpha and finalAlpha will ensure               
2681 -        // ensure that only the current page is visible during (and subsequently, after) the                      
2682 -        // transition animation.  If fade adjacent pages is disabled, then re-enable the page                     
2683 -        // visibility after the transition animation.                                                             
2684 -        if (!mWorkspaceFadeInAdjacentScreens) {                                                                   
2685 -            for (int i = 0; i < getChildCount(); i++) {                                                           
2686 -                final CellLayout cl = (CellLayout) getChildAt(i);                                                 
2687 -                cl.setShortcutAndWidgetAlpha(1f);                                                                 
2688 -            }                                                                                                     
2689 -        } else {                                                                                                  
2690 -            for (int i = 0; i < numCustomPages(); i++) {                                                          
2691 -                final CellLayout cl = (CellLayout) getChildAt(i);                                                 
2692 -                cl.setShortcutAndWidgetAlpha(1f);                                                                 
2693 -            }                                                                                                     
2694 -        }                                                                                                         
2695          showCustomContentIfNecessary();                                                                           
2696      }                                                                                                             
2697                                                                                                                    
2698      @Override                                                                                                     
2699      public View getContent() {                                                                                    
2700          return this;                                                                                              
2701      }                                                                                                             
2702                                                                                                                    
2703      /**                                                                                                           
2704       * Draw the View v into the given Canvas.                                                                     
2705       *                                                                                                            
2706       * @param v the view to draw                                                                                  
2707       * @param destCanvas the canvas to draw on                                                                    
2708       * @param padding the horizontal and vertical padding to use when drawing                                     
2709       */                                                                                                           
2710 -    private void drawDragView(View v, Canvas destCanvas, int padding, boolean pruneToDrawable) {                  
2711 -        final Rect clipRect = mTempRect;                                                                          
2712 +    private static void drawDragView(View v, Canvas destCanvas, int padding) {                                    
2713 +        final Rect clipRect = sTempRect;                                                                          
2714          v.getDrawingRect(clipRect);                                                                               
2715                                                                                                                    
2716          boolean textVisible = false;                                                                              
2717                                                                                                                    
2718          destCanvas.save();                                                                                        
2719 -        if (v instanceof TextView && pruneToDrawable) {                                                           
2720 +        if (v instanceof TextView) {                                                                              
2721              Drawable d = ((TextView) v).getCompoundDrawables()[1];                                                
2722 -            clipRect.set(0, 0, d.getIntrinsicWidth() + padding, d.getIntrinsicHeight() + padding);                
2723 -            destCanvas.translate(padding / 2, padding / 2);                                                       
2724 +            Rect bounds = getDrawableBounds(d);                                                                   
2725 +            clipRect.set(0, 0, bounds.width() + padding, bounds.height() + padding);                              
2726 +            destCanvas.translate(padding / 2 - bounds.left, padding / 2 - bounds.top);                            
2727              d.draw(destCanvas);                                                                                   
2728          } else {                                                                                                  
2729              if (v instanceof FolderIcon) {                                                                        
2730                  // For FolderIcons the text can bleed into the icon area, and so we need to                       
2731                  // hide the text completely (which can't be achieved by clipping).                                
2732                  if (((FolderIcon) v).getTextVisible()) {                                                          
2733                      ((FolderIcon) v).setTextVisible(false);                                                       
2734                      textVisible = true;                                                                           
2735                  }                                                                                                 
2736 -            } else if (v instanceof BubbleTextView) {                                                             
2737 -                final BubbleTextView tv = (BubbleTextView) v;                                                     
2738 -                clipRect.bottom = tv.getExtendedPaddingTop() - (int) BubbleTextView.PADDING_V +                   
2739 -                        tv.getLayout().getLineTop(0);                                                             
2740 -            } else if (v instanceof TextView) {                                                                   
2741 -                final TextView tv = (TextView) v;                                                                 
2742 -                clipRect.bottom = tv.getExtendedPaddingTop() - tv.getCompoundDrawablePadding() +                  
2743 -                        tv.getLayout().getLineTop(0);                                                             
2744              }                                                                                                     
2745              destCanvas.translate(-v.getScrollX() + padding / 2, -v.getScrollY() + padding / 2);                   
2746              destCanvas.clipRect(clipRect, Op.REPLACE);                                                            
2747              v.draw(destCanvas);                                                                                   
2748                                                                                                                    
2749              // Restore text visibility of FolderIcon if necessary                                                 
2750              if (textVisible) {                                                                                    
2751                  ((FolderIcon) v).setTextVisible(true);                                                            
2752              }                                                                                                     
2753          }                                                                                                         
2754          destCanvas.restore();                                                                                     
2755      }                                                                                                             
2756                                                                                                                    
2757      /**                                                                                                           
2758       * Returns a new bitmap to show when the given View is being dragged around.                                  
2759       * Responsibility for the bitmap is transferred to the caller.                                                
2760 +     * @param expectedPadding padding to add to the drag view. If a different padding was used                    
2761 +     * its value will be changed                                                                                  
2762       */                                                                                                           
2763 -    public Bitmap createDragBitmap(View v, Canvas canvas, int padding) {                                          
2764 +    public Bitmap createDragBitmap(View v, AtomicInteger expectedPadding) {                                       
2765          Bitmap b;                                                                                                 
2766                                                                                                                    
2767 +        int padding = expectedPadding.get();                                                                      
2768          if (v instanceof TextView) {                                                                              
2769              Drawable d = ((TextView) v).getCompoundDrawables()[1];                                                
2770 -            b = Bitmap.createBitmap(d.getIntrinsicWidth() + padding,                                              
2771 -                    d.getIntrinsicHeight() + padding, Bitmap.Config.ARGB_8888);                                   
2772 +            Rect bounds = getDrawableBounds(d);                                                                   
2773 +            b = Bitmap.createBitmap(bounds.width() + padding,                                                     
2774 +                    bounds.height() + padding, Bitmap.Config.ARGB_8888);                                          
2775 +            expectedPadding.set(padding - bounds.left - bounds.top);                                              
2776          } else {                                                                                                  
2777              b = Bitmap.createBitmap(                                                                              
2778                      v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);                    
2779          }                                                                                                         
2780                                                                                                                    
2781 -        canvas.setBitmap(b);                                                                                      
2782 -        drawDragView(v, canvas, padding, true);                                                                   
2783 -        canvas.setBitmap(null);                                                                                   
2784 +        mCanvas.setBitmap(b);                                                                                     
2785 +        drawDragView(v, mCanvas, padding);                                                                        
2786 +        mCanvas.setBitmap(null);                                                                                  
2787                                                                                                                    
2788          return b;                                                                                                 
2789      }                                                                                                             
2790                                                                                                                    
2791      /**                                                                                                           
2792       * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.                
2793       * Responsibility for the bitmap is transferred to the caller.                                                
2794       */                                                                                                           
2795 -    private Bitmap createDragOutline(View v, Canvas canvas, int padding) {                                        
2796 +    private Bitmap createDragOutline(View v, int padding) {                                                       
2797          final int outlineColor = getResources().getColor(R.color.outline_color);                                  
2798          final Bitmap b = Bitmap.createBitmap(                                                                     
2799                  v.getWidth() + padding, v.getHeight() + padding, Bitmap.Config.ARGB_8888);                        
2800                                                                                                                    
2801 -        canvas.setBitmap(b);                                                                                      
2802 -        drawDragView(v, canvas, padding, true);                                                                   
2803 -        mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor);                
2804 -        canvas.setBitmap(null);                                                                                   
2805 +        mCanvas.setBitmap(b);                                                                                     
2806 +        drawDragView(v, mCanvas, padding);                                                                        
2807 +        mOutlineHelper.applyExpensiveOutlineWithBlur(b, mCanvas, outlineColor, outlineColor);                     
2808 +        mCanvas.setBitmap(null);                                                                                  
2809          return b;                                                                                                 
2810      }                                                                                                             
2811                                                                                                                    
2812      /**                                                                                                           
2813       * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.                
2814       * Responsibility for the bitmap is transferred to the caller.                                                
2815       */                                                                                                           
2816 -    private Bitmap createDragOutline(Bitmap orig, Canvas canvas, int padding, int w, int h,                       
2817 +    private Bitmap createDragOutline(Bitmap orig, int padding, int w, int h,                                      
2818              boolean clipAlpha) {                                                                                  
2819          final int outlineColor = getResources().getColor(R.color.outline_color);                                  
2820          final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);                                      
2821 -        canvas.setBitmap(b);                                                                                      
2822 +        mCanvas.setBitmap(b);                                                                                     
2823                                                                                                                    
2824          Rect src = new Rect(0, 0, orig.getWidth(), orig.getHeight());                                             
2825          float scaleFactor = Math.min((w - padding) / (float) orig.getWidth(),                                     
2826                  (h - padding) / (float) orig.getHeight());                                                        
2827          int scaledWidth = (int) (scaleFactor * orig.getWidth());                                                  
2828          int scaledHeight = (int) (scaleFactor * orig.getHeight());                                                
2829          Rect dst = new Rect(0, 0, scaledWidth, scaledHeight);                                                     
2830                                                                                                                    
2831          // center the image                                                                                       
2832          dst.offset((w - scaledWidth) / 2, (h - scaledHeight) / 2);                                                
2833                                                                                                                    
2834 -        canvas.drawBitmap(orig, src, dst, null);                                                                  
2835 -        mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor,                 
2836 +        mCanvas.drawBitmap(orig, src, dst, null);                                                                 
2837 +        mOutlineHelper.applyExpensiveOutlineWithBlur(b, mCanvas, outlineColor, outlineColor,                      
2838                  clipAlpha);                                                                                       
2839 -        canvas.setBitmap(null);                                                                                   
2840 +        mCanvas.setBitmap(null);                                                                                  
2841                                                                                                                    
2842          return b;                                                                                                 
2843      }                                                                                                             
2844                                                                                                                    
2845      void startDrag(CellLayout.CellInfo cellInfo) {                                                                
2846          View child = cellInfo.cell;                                                                               
2847                                                                                                                    
2848          // Make sure the drag was started by a long press as opposed to a long click.                             
2849          if (!child.isInTouchMode()) {                                                                             
2850              return;                                                                                               
2851          }                                                                                                         
2852                                                                                                                    
2853          mDragInfo = cellInfo;                                                                                     
2854          child.setVisibility(INVISIBLE);                                                                           
2855          CellLayout layout = (CellLayout) child.getParent().getParent();                                           
2856          layout.prepareChildForDrag(child);                                                                        
2857                                                                                                                    
2858 +        beginDragShared(child, this);                                                                             
2859 +    }                                                                                                             
2860 +                                                                                                                  
2861 +    public void beginDragShared(View child, DragSource source) {                                                  
2862          child.clearFocus();                                                                                       
2863          child.setPressed(false);                                                                                  
2864                                                                                                                    
2865 -        final Canvas canvas = new Canvas();                                                                       
2866 -                                                                                                                  
2867          // The outline is used to visualize where the item will land if dropped                                   
2868 -        mDragOutline = createDragOutline(child, canvas, DRAG_BITMAP_PADDING);                                     
2869 -        beginDragShared(child, this);                                                                             
2870 -    }                                                                                                             
2871 -                                                                                                                  
2872 -    public void beginDragShared(View child, DragSource source) {                                                  
2873 +        mDragOutline = createDragOutline(child, DRAG_BITMAP_PADDING);                                             
2874 +                                                                                                                  
2875 +        mLauncher.onDragStarted(child);                                                                           
2876          // The drag bitmap follows the touch point around on the screen                                           
2877 -        final Bitmap b = createDragBitmap(child, new Canvas(), DRAG_BITMAP_PADDING);                              
2878 +        AtomicInteger padding = new AtomicInteger(DRAG_BITMAP_PADDING);                                           
2879 +        final Bitmap b = createDragBitmap(child, padding);                                                        
2880                                                                                                                    
2881          final int bmpWidth = b.getWidth();                                                                        
2882          final int bmpHeight = b.getHeight();                                                                      
2883                                                                                                                    
2884          float scale = mLauncher.getDragLayer().getLocationInDragLayer(child, mTempXY);                            
2885 -        int dragLayerX =                                                                                          
2886 -                Math.round(mTempXY[0] - (bmpWidth - scale * child.getWidth()) / 2);                               
2887 -        int dragLayerY =                                                                                          
2888 -                Math.round(mTempXY[1] - (bmpHeight - scale * bmpHeight) / 2                                       
2889 -                        - DRAG_BITMAP_PADDING / 2);                                                               
2890 +        int dragLayerX = Math.round(mTempXY[0] - (bmpWidth - scale * child.getWidth()) / 2);                      
2891 +        int dragLayerY = Math.round(mTempXY[1] - (bmpHeight - scale * bmpHeight) / 2                              
2892 +                        - padding.get() / 2);                                                                     
2893                                                                                                                    
2894          LauncherAppState app = LauncherAppState.getInstance();                                                    
2895          DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                             
2896          Point dragVisualizeOffset = null;                                                                         
2897          Rect dragRect = null;                                                                                     
2898 -        if (child instanceof BubbleTextView || child instanceof PagedViewIcon) {                                  
2899 +        if (child instanceof BubbleTextView) {                                                                    
2900              int iconSize = grid.iconSizePx;                                                                       
2901              int top = child.getPaddingTop();                                                                      
2902              int left = (bmpWidth - iconSize) / 2;                                                                 
2903              int right = left + iconSize;                                                                          
2904              int bottom = top + iconSize;                                                                          
2905              dragLayerY += top;                                                                                    
2906              // Note: The drag region is used to calculate drag layer offsets, but the                             
2907              // dragVisualizeOffset in addition to the dragRect (the size) to position the outline.                
2908 -            dragVisualizeOffset = new Point(-DRAG_BITMAP_PADDING / 2, DRAG_BITMAP_PADDING / 2);                   
2909 +            dragVisualizeOffset = new Point(-padding.get() / 2, padding.get() / 2);                               
2910              dragRect = new Rect(left, top, right, bottom);                                                        
2911          } else if (child instanceof FolderIcon) {                                                                 
2912              int previewSize = grid.folderIconSizePx;                                                              
2913              dragRect = new Rect(0, child.getPaddingTop(), child.getWidth(), previewSize);                         
2914          }                                                                                                         
2915                                                                                                                    
2916          // Clear the pressed state if necessary                                                                   
2917          if (child instanceof BubbleTextView) {                                                                    
2918              BubbleTextView icon = (BubbleTextView) child;                                                         
2919 -            icon.clearPressedOrFocusedBackground();                                                               
2920 +            icon.clearPressedBackground();                                                                        
2921          }                                                                                                         
2922                                                                                                                    
2923          if (child.getTag() == null || !(child.getTag() instanceof ItemInfo)) {                                    
2924              String msg = "Drag started with a view that has no tag set. This "                                    
2925                      + "will cause a crash (issue 11627249) down the line. "                                       
2926                      + "View: " + child + "  tag: " + child.getTag();                                              
2927              throw new IllegalStateException(msg);                                                                 
2928          }                                                                                                         
2929                                                                                                                    
2930          DragView dv = mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(),                
2931                  DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, scale);                           
2932          dv.setIntrinsicIconScaleFactor(source.getIntrinsicIconScaleFactor());                                     
2933                                                                                                                    
2934          if (child.getParent() instanceof ShortcutAndWidgetContainer) {                                            
2935              mDragSourceInternal = (ShortcutAndWidgetContainer) child.getParent();                                 
2936          }                                                                                                         
2937                                                                                                                    
2938          b.recycle();                                                                                              
2939      }                                                                                                             
2940                                                                                                                    
2941 +    public void beginExternalDragShared(View child, DragSource source) {                                          
2942 +        LauncherAppState app = LauncherAppState.getInstance();                                                    
2943 +        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                             
2944 +        int iconSize = grid.iconSizePx;                                                                           
2945 +                                                                                                                  
2946 +        // Notify launcher of drag start                                                                          
2947 +        mLauncher.onDragStarted(child);                                                                           
2948 +                                                                                                                  
2949 +        // Compose a new drag bitmap that is of the icon size                                                     
2950 +        AtomicInteger padding = new AtomicInteger(DRAG_BITMAP_PADDING);                                           
2951 +        final Bitmap tmpB = createDragBitmap(child, padding);                                                     
2952 +        Bitmap b = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);                              
2953 +        Paint p = new Paint();                                                                                    
2954 +        p.setFilterBitmap(true);                                                                                  
2955 +        mCanvas.setBitmap(b);                                                                                     
2956 +        mCanvas.drawBitmap(tmpB, new Rect(0, 0, tmpB.getWidth(), tmpB.getHeight()),                               
2957 +                new Rect(0, 0, iconSize, iconSize), p);                                                           
2958 +        mCanvas.setBitmap(null);                                                                                  
2959 +                                                                                                                  
2960 +        // Find the child's location on the screen                                                                
2961 +        int bmpWidth = tmpB.getWidth();                                                                           
2962 +        float iconScale = (float) bmpWidth / iconSize;                                                            
2963 +        float scale = mLauncher.getDragLayer().getLocationInDragLayer(child, mTempXY) * iconScale;                
2964 +        int dragLayerX = Math.round(mTempXY[0] - (bmpWidth - scale * child.getWidth()) / 2);                      
2965 +        int dragLayerY = Math.round(mTempXY[1]);                                                                  
2966 +                                                                                                                  
2967 +        // Note: The drag region is used to calculate drag layer offsets, but the                                 
2968 +        // dragVisualizeOffset in addition to the dragRect (the size) to position the outline.                    
2969 +        Point dragVisualizeOffset = new Point(-padding.get() / 2, padding.get() / 2);                             
2970 +        Rect dragRect = new Rect(0, 0, iconSize, iconSize);                                                       
2971 +                                                                                                                  
2972 +        if (child.getTag() == null || !(child.getTag() instanceof ItemInfo)) {                                    
2973 +            String msg = "Drag started with a view that has no tag set. This "                                    
2974 +                    + "will cause a crash (issue 11627249) down the line. "                                       
2975 +                    + "View: " + child + "  tag: " + child.getTag();                                              
2976 +            throw new IllegalStateException(msg);                                                                 
2977 +        }                                                                                                         
2978 +                                                                                                                  
2979 +        // Start the drag                                                                                         
2980 +        DragView dv = mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(),                
2981 +                DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, scale);                           
2982 +        dv.setIntrinsicIconScaleFactor(source.getIntrinsicIconScaleFactor());                                     
2983 +                                                                                                                  
2984 +        // Recycle temporary bitmaps                                                                              
2985 +        tmpB.recycle();                                                                                           
2986 +    }                                                                                                             
2987 +                                                                                                                  
2988      void addApplicationShortcut(ShortcutInfo info, CellLayout target, long container, long screenId,              
2989              int cellX, int cellY, boolean insertAtFirst, int intersectX, int intersectY) {                        
2990          View view = mLauncher.createShortcut(R.layout.application, target, (ShortcutInfo) info);                  
2991                                                                                                                    
2992          final int[] cellXY = new int[2];                                                                          
2993          target.findCellForSpanThatIntersects(cellXY, 1, 1, intersectX, intersectY);                               
2994          addInScreen(view, container, screenId, cellXY[0], cellXY[1], 1, 1, insertAtFirst);                        
2995                                                                                                                    
2996          LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screenId, cellXY[0],                    
2997                  cellXY[1]);                                                                                       
2998      }                                                                                                             
2999                                                                                                                    
3000      public boolean transitionStateShouldAllowDrop() {                                                             
3001 -        return ((!isSwitchingState() || mTransitionProgress > 0.5f) && mState != State.SMALL);                    
3002 +        return ((!isSwitchingState() || mTransitionProgress > 0.5f) &&                                            
3003 +                (mState == State.NORMAL || mState == State.SPRING_LOADED));                                       
3004      }                                                                                                             
3005                                                                                                                    
3006      /**                                                                                                           
3007       * {@inheritDoc}                                                                                              
3008       */                                                                                                           
3009      public boolean acceptDrop(DragObject d) {                                                                     
3010          // If it's an external drop (e.g. from All Apps), check if it should be accepted                          
3011          CellLayout dropTargetLayout = mDropToLayout;                                                              
3012          if (d.dragSource != this) {                                                                               
3013              // Don't accept the drop if we're not over a screen at time of drop                                   
3014              if (dropTargetLayout == null) {                                                                       
3015                  return false;                                                                                     
3016              }                                                                                                     
3017              if (!transitionStateShouldAllowDrop()) return false;                                                  
3018                                                                                                                    
3019              mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset,                       
3020                      d.dragView, mDragViewVisualCenter);                                                           
3021                                                                                                                    
3022              // We want the point to be mapped to the dragTarget.                                                  
3023              if (mLauncher.isHotseatLayout(dropTargetLayout)) {                                                    
3024                  mapPointFromSelfToHotseatLayout(mLauncher.getHotseat(), mDragViewVisualCenter);                   
3025              } else {                                                                                              
3026                  mapPointFromSelfToChild(dropTargetLayout, mDragViewVisualCenter, null);                           
3027              }                                                                                                     
3028                                                                                                                    
3029              int spanX = 1;                                                                                        
3030              int spanY = 1;                                                                                        
3031              if (mDragInfo != null) {                                                                              
3032                  final CellLayout.CellInfo dragCellInfo = mDragInfo;                                               
3033                  spanX = dragCellInfo.spanX;                                                                       
3034                  spanY = dragCellInfo.spanY;                                                                       
3035              } else {                                                                                              
3036                  final ItemInfo dragInfo = (ItemInfo) d.dragInfo;                                                  
3037                  spanX = dragInfo.spanX;                                                                           
3038                  spanY = dragInfo.spanY;                                                                           
3039              }                                                                                                     
3040                                                                                                                    
3041              int minSpanX = spanX;                                                                                 
3042              int minSpanY = spanY;                                                                                 
3043              if (d.dragInfo instanceof PendingAddWidgetInfo) {                                                     
3044                  minSpanX = ((PendingAddWidgetInfo) d.dragInfo).minSpanX;                                          
3045                  minSpanY = ((PendingAddWidgetInfo) d.dragInfo).minSpanY;                                          
3046              }                                                                                                     
3047                                                                                                                    
3048              mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],                                         
3049                      (int) mDragViewVisualCenter[1], minSpanX, minSpanY, dropTargetLayout,                         
3050                      mTargetCell);                                                                                 
3051              float distance = dropTargetLayout.getDistanceFromCell(mDragViewVisualCenter[0],                       
3052                      mDragViewVisualCenter[1], mTargetCell);                                                       
3053 -            if (willCreateUserFolder((ItemInfo) d.dragInfo, dropTargetLayout,                                     
3054 -                    mTargetCell, distance, true)) {                                                               
3055 +            if (mCreateUserFolderOnDrop && willCreateUserFolder((ItemInfo) d.dragInfo,                            
3056 +                    dropTargetLayout, mTargetCell, distance, true)) {                                             
3057                  return true;                                                                                      
3058              }                                                                                                     
3059 -            if (willAddToExistingUserFolder((ItemInfo) d.dragInfo, dropTargetLayout,                              
3060 -                    mTargetCell, distance)) {                                                                     
3061 +                                                                                                                  
3062 +            if (mAddToExistingFolderOnDrop && willAddToExistingUserFolder((ItemInfo) d.dragInfo,                  
3063 +                    dropTargetLayout, mTargetCell, distance)) {                                                   
3064                  return true;                                                                                      
3065              }                                                                                                     
3066                                                                                                                    
3067              int[] resultSpan = new int[2];                                                                        
3068              mTargetCell = dropTargetLayout.performReorder((int) mDragViewVisualCenter[0],                         
3069                      (int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY,                             
3070                      null, mTargetCell, resultSpan, CellLayout.MODE_ACCEPT_DROP);                                  
3071              boolean foundCell = mTargetCell[0] >= 0 && mTargetCell[1] >= 0;                                       
3072                                                                                                                    
3073              // Don't accept the drop if there's no room for the item                                              
3074              if (!foundCell) {                                                                                     
3075                  // Don't show the message if we are dropping on the AllApps button and the hotseat                
3076                  // is full                                                                                        
3077                  boolean isHotseat = mLauncher.isHotseatLayout(dropTargetLayout);                                  
3078                  if (mTargetCell != null && isHotseat) {                                                           
3079                      Hotseat hotseat = mLauncher.getHotseat();                                                     
3080                      if (hotseat.isAllAppsButtonRank(                                                              
3081                              hotseat.getOrderInHotseat(mTargetCell[0], mTargetCell[1]))) {                         
3082                          return false;                                                                             
3083                      }                                                                                             
3084                  }                                                                                                 
3085                                                                                                                    
3086                  mLauncher.showOutOfSpaceMessage(isHotseat);                                                       
3087                  return false;                                                                                     
3088              }                                                                                                     
3089          }                                                                                                         
3090                                                                                                                    
3091          long screenId = getIdForScreen(dropTargetLayout);                                                         
3092          if (screenId == EXTRA_EMPTY_SCREEN_ID) {                                                                  
3093              commitExtraEmptyScreen();                                                                             
3094          }                                                                                                         
3095                                                                                                                    
3096          return true;                                                                                              
3097      }                                                                                                             
3098                                                                                                                    
3099      boolean willCreateUserFolder(ItemInfo info, CellLayout target, int[] targetCell, float                        
3100              distance, boolean considerTimeout) {                                                                  
3101          if (distance > mMaxDistanceForFolderCreation) return false;                                               
3102          View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);                                      
3103                                                                                                                    
3104          if (dropOverView != null) {                                                                               
3105              CellLayout.LayoutParams lp = (CellLayout.LayoutParams) dropOverView.getLayoutParams();                
3106              if (lp.useTmpCoords && (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.tmpCellY)) {                     
3107                  return false;                                                                                     
3108              }                                                                                                     
3109          }                                                                                                         
3110                                                                                                                    
3111          boolean hasntMoved = false;                                                                               
3112          if (mDragInfo != null) {                                                                                  
3113              hasntMoved = dropOverView == mDragInfo.cell;                                                          
3114          }                                                                                                         
3115                                                                                                                    
3116          if (dropOverView == null || hasntMoved || (considerTimeout && !mCreateUserFolderOnDrop)) {                
3117              return false;                                                                                         
3118          }                                                                                                         
3119                                                                                                                    
3120          boolean aboveShortcut = (dropOverView.getTag() instanceof ShortcutInfo);                                  
3121          boolean willBecomeShortcut =                                                                              
3122                  (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||                             
3123                  info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT);                                  
3124                                                                                                                    
3125          return (aboveShortcut && willBecomeShortcut);                                                             
3126      }                                                                                                             
3127                                                                                                                    
3128      boolean willAddToExistingUserFolder(Object dragInfo, CellLayout target, int[] targetCell,                     
3129              float distance) {                                                                                     
3130          if (distance > mMaxDistanceForFolderCreation) return false;                                               
3131          View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);                                      
3132                                                                                                                    
3133          if (dropOverView != null) {                                                                               
3134              CellLayout.LayoutParams lp = (CellLayout.LayoutParams) dropOverView.getLayoutParams();                
3135              if (lp.useTmpCoords && (lp.tmpCellX != lp.cellX || lp.tmpCellY != lp.tmpCellY)) {                     
3136                  return false;                                                                                     
3137              }                                                                                                     
3138          }                                                                                                         
3139                                                                                                                    
3140          if (dropOverView instanceof FolderIcon) {                                                                 
3141              FolderIcon fi = (FolderIcon) dropOverView;                                                            
3142              if (fi.acceptDrop(dragInfo)) {                                                                        
3143                  return true;                                                                                      
3144              }                                                                                                     
3145          }                                                                                                         
3146          return false;                                                                                             
3147      }                                                                                                             
3148                                                                                                                    
3149      boolean createUserFolderIfNecessary(View newView, long container, CellLayout target,                          
3150              int[] targetCell, float distance, boolean external, DragView dragView,                                
3151              Runnable postAnimationRunnable) {                                                                     
3152          if (distance > mMaxDistanceForFolderCreation) return false;                                               
3153          View v = target.getChildAt(targetCell[0], targetCell[1]);                                                 
3154                                                                                                                    
3155          boolean hasntMoved = false;                                                                               
3156          if (mDragInfo != null) {                                                                                  
3157              CellLayout cellParent = getParentCellLayoutForView(mDragInfo.cell);                                   
3158              hasntMoved = (mDragInfo.cellX == targetCell[0] &&                                                     
3159                      mDragInfo.cellY == targetCell[1]) && (cellParent == target);                                  
3160          }                                                                                                         
3161                                                                                                                    
3162          if (v == null || hasntMoved || !mCreateUserFolderOnDrop) return false;                                    
3163          mCreateUserFolderOnDrop = false;                                                                          
3164          final long screenId = (targetCell == null) ? mDragInfo.screenId : getIdForScreen(target);                 
3165                                                                                                                    
3166          boolean aboveShortcut = (v.getTag() instanceof ShortcutInfo);                                             
3167          boolean willBecomeShortcut = (newView.getTag() instanceof ShortcutInfo);                                  
3168                                                                                                                    
3169          if (aboveShortcut && willBecomeShortcut) {                                                                
3170              ShortcutInfo sourceInfo = (ShortcutInfo) newView.getTag();                                            
3171              ShortcutInfo destInfo = (ShortcutInfo) v.getTag();                                                    
3172              // if the drag started here, we need to remove it from the workspace                                  
3173              if (!external) {                                                                                      
3174                  getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell);                            
3175              }                                                                                                     
3176                                                                                                                    
3177              Rect folderLocation = new Rect();                                                                     
3178              float scale = mLauncher.getDragLayer().getDescendantRectRelativeToSelf(v, folderLocation);            
3179              target.removeView(v);                                                                                 
3180                                                                                                                    
3181              FolderIcon fi =                                                                                       
3182                  mLauncher.addFolder(target, container, screenId, targetCell[0], targetCell[1]);                   
3183              destInfo.cellX = -1;                                                                                  
3184              destInfo.cellY = -1;                                                                                  
3185              sourceInfo.cellX = -1;                                                                                
3186              sourceInfo.cellY = -1;                                                                                
3187                                                                                                                    
3188              // If the dragView is null, we can't animate                                                          
3189              boolean animate = dragView != null;                                                                   
3190              if (animate) {                                                                                        
3191                  fi.performCreateAnimation(destInfo, v, sourceInfo, dragView, folderLocation, scale,               
3192                          postAnimationRunnable);                                                                   
3193              } else {                                                                                              
3194                  fi.addItem(destInfo);                                                                             
3195                  fi.addItem(sourceInfo);                                                                           
3196              }                                                                                                     
3197              return true;                                                                                          
3198          }                                                                                                         
3199          return false;                                                                                             
3200      }                                                                                                             
3201                                                                                                                    
3202      boolean addToExistingFolderIfNecessary(View newView, CellLayout target, int[] targetCell,                     
3203              float distance, DragObject d, boolean external) {                                                     
3204          if (distance > mMaxDistanceForFolderCreation) return false;                                               
3205                                                                                                                    
3206          View dropOverView = target.getChildAt(targetCell[0], targetCell[1]);                                      
3207          if (!mAddToExistingFolderOnDrop) return false;                                                            
3208          mAddToExistingFolderOnDrop = false;                                                                       
3209                                                                                                                    
3210          if (dropOverView instanceof FolderIcon) {                                                                 
3211              FolderIcon fi = (FolderIcon) dropOverView;                                                            
3212              if (fi.acceptDrop(d.dragInfo)) {                                                                      
3213                  fi.onDrop(d);                                                                                     
3214                                                                                                                    
3215                  // if the drag started here, we need to remove it from the workspace                              
3216                  if (!external) {                                                                                  
3217                      getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell);                        
3218                  }                                                                                                 
3219                  return true;                                                                                      
3220              }                                                                                                     
3221          }                                                                                                         
3222          return false;                                                                                             
3223      }                                                                                                             
3224                                                                                                                    
3225      public void onDrop(final DragObject d) {                                                                      
3226          mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, d.dragView,               
3227                  mDragViewVisualCenter);                                                                           
3228                                                                                                                    
3229          CellLayout dropTargetLayout = mDropToLayout;                                                              
3230                                                                                                                    
3231          // We want the point to be mapped to the dragTarget.                                                      
3232          if (dropTargetLayout != null) {                                                                           
3233              if (mLauncher.isHotseatLayout(dropTargetLayout)) {                                                    
3234                  mapPointFromSelfToHotseatLayout(mLauncher.getHotseat(), mDragViewVisualCenter);                   
3235              } else {                                                                                              
3236                  mapPointFromSelfToChild(dropTargetLayout, mDragViewVisualCenter, null);                           
3237              }                                                                                                     
3238          }                                                                                                         
3239                                                                                                                    
3240          int snapScreen = -1;                                                                                      
3241          boolean resizeOnDrop = false;                                                                             
3242          if (d.dragSource != this) {                                                                               
3243              final int[] touchXY = new int[] { (int) mDragViewVisualCenter[0],                                     
3244                      (int) mDragViewVisualCenter[1] };                                                             
3245              onDropExternal(touchXY, d.dragInfo, dropTargetLayout, false, d);                                      
3246          } else if (mDragInfo != null) {                                                                           
3247              final View cell = mDragInfo.cell;                                                                     
3248                                                                                                                    
3249              Runnable resizeRunnable = null;                                                                       
3250              if (dropTargetLayout != null && !d.cancelled) {                                                       
3251                  // Move internally                                                                                
3252                  boolean hasMovedLayouts = (getParentCellLayoutForView(cell) != dropTargetLayout);                 
3253                  boolean hasMovedIntoHotseat = mLauncher.isHotseatLayout(dropTargetLayout);                        
3254                  long container = hasMovedIntoHotseat ?                                                            
3255                          LauncherSettings.Favorites.CONTAINER_HOTSEAT :                                            
3256                          LauncherSettings.Favorites.CONTAINER_DESKTOP;                                             
3257                  long screenId = (mTargetCell[0] < 0) ?                                                            
3258                          mDragInfo.screenId : getIdForScreen(dropTargetLayout);                                    
3259                  int spanX = mDragInfo != null ? mDragInfo.spanX : 1;                                              
3260                  int spanY = mDragInfo != null ? mDragInfo.spanY : 1;                                              
3261                  // First we find the cell nearest to point at which the item is                                   
3262                  // dropped, without any consideration to whether there is an item there.                          
3263                                                                                                                    
3264                  mTargetCell = findNearestArea((int) mDragViewVisualCenter[0], (int)                               
3265                          mDragViewVisualCenter[1], spanX, spanY, dropTargetLayout, mTargetCell);                   
3266                  float distance = dropTargetLayout.getDistanceFromCell(mDragViewVisualCenter[0],                   
3267                          mDragViewVisualCenter[1], mTargetCell);                                                   
3268                                                                                                                    
3269                  // If the item being dropped is a shortcut and the nearest drop                                   
3270                  // cell also contains a shortcut, then create a folder with the two shortcuts.                    
3271                  if (!mInScrollArea && createUserFolderIfNecessary(cell, container,                                
3272                          dropTargetLayout, mTargetCell, distance, false, d.dragView, null)) {                      
3273 -                    removeExtraEmptyScreen(true, null, 0, true);                                                  
3274                      return;                                                                                       
3275                  }                                                                                                 
3276                                                                                                                    
3277                  if (addToExistingFolderIfNecessary(cell, dropTargetLayout, mTargetCell,                           
3278                          distance, d, false)) {                                                                    
3279 -                    removeExtraEmptyScreen(true, null, 0, true);                                                  
3280                      return;                                                                                       
3281                  }                                                                                                 
3282                                                                                                                    
3283                  // Aside from the special case where we're dropping a shortcut onto a shortcut,                   
3284                  // we need to find the nearest cell location that is vacant                                       
3285                  ItemInfo item = (ItemInfo) d.dragInfo;                                                            
3286                  int minSpanX = item.spanX;                                                                        
3287                  int minSpanY = item.spanY;                                                                        
3288                  if (item.minSpanX > 0 && item.minSpanY > 0) {                                                     
3289                      minSpanX = item.minSpanX;                                                                     
3290                      minSpanY = item.minSpanY;                                                                     
3291                  }                                                                                                 
3292                                                                                                                    
3293                  int[] resultSpan = new int[2];                                                                    
3294                  mTargetCell = dropTargetLayout.performReorder((int) mDragViewVisualCenter[0],                     
3295                          (int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY, cell,                   
3296                          mTargetCell, resultSpan, CellLayout.MODE_ON_DROP);                                        
3297                                                                                                                    
3298                  boolean foundCell = mTargetCell[0] >= 0 && mTargetCell[1] >= 0;                                   
3299                                                                                                                    
3300                  // if the widget resizes on drop                                                                  
3301                  if (foundCell && (cell instanceof AppWidgetHostView) &&                                           
3302                          (resultSpan[0] != item.spanX || resultSpan[1] != item.spanY)) {                           
3303                      resizeOnDrop = true;                                                                          
3304                      item.spanX = resultSpan[0];                                                                   
3305                      item.spanY = resultSpan[1];                                                                   
3306                      AppWidgetHostView awhv = (AppWidgetHostView) cell;                                            
3307                      AppWidgetResizeFrame.updateWidgetSizeRanges(awhv, mLauncher, resultSpan[0],                   
3308                              resultSpan[1]);                                                                       
3309                  }                                                                                                 
3310                                                                                                                    
3311                  if (getScreenIdForPageIndex(mCurrentPage) != screenId && !hasMovedIntoHotseat) {                  
3312                      snapScreen = getPageIndexForScreenId(screenId);                                               
3313                      snapToPage(snapScreen);                                                                       
3314                  }                                                                                                 
3315                                                                                                                    
3316                  if (foundCell) {                                                                                  
3317                      final ItemInfo info = (ItemInfo) cell.getTag();                                               
3318                      if (hasMovedLayouts) {                                                                        
3319                          // Reparent the view                                                                      
3320 -                        getParentCellLayoutForView(cell).removeView(cell);                                        
3321 +                        CellLayout parentCell = getParentCellLayoutForView(cell);                                 
3322 +                        if (parentCell != null) {                                                                 
3323 +                            parentCell.removeView(cell);                                                          
3324 +                        } else if (LauncherAppState.isDogfoodBuild()) {                                           
3325 +                            throw new NullPointerException("mDragInfo.cell has null parent");                     
3326 +                        }                                                                                         
3327                          addInScreen(cell, container, screenId, mTargetCell[0], mTargetCell[1],                    
3328                                  info.spanX, info.spanY);                                                          
3329                      }                                                                                             
3330                                                                                                                    
3331                      // update the item's position after drop                                                      
3332                      CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();                
3333                      lp.cellX = lp.tmpCellX = mTargetCell[0];                                                      
3334                      lp.cellY = lp.tmpCellY = mTargetCell[1];                                                      
3335                      lp.cellHSpan = item.spanX;                                                                    
3336                      lp.cellVSpan = item.spanY;                                                                    
3337                      lp.isLockedToGrid = true;                                                                     
3338                                                                                                                    
3339                      if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT &&                              
3340                              cell instanceof LauncherAppWidgetHostView) {                                          
3341                          final CellLayout cellLayout = dropTargetLayout;                                           
3342                          // We post this call so that the widget has a chance to be placed                         
3343                          // in its final location                                                                  
3344                                                                                                                    
3345                          final LauncherAppWidgetHostView hostView = (LauncherAppWidgetHostView) cell;              
3346                          AppWidgetProviderInfo pinfo = hostView.getAppWidgetInfo();                                
3347                          if (pinfo != null &&                                                                      
3348                                  pinfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE) {                          
3349                              final Runnable addResizeFrame = new Runnable() {                                      
3350                                  public void run() {                                                               
3351                                      DragLayer dragLayer = mLauncher.getDragLayer();                               
3352                                      dragLayer.addResizeFrame(info, hostView, cellLayout);                         
3353                                  }                                                                                 
3354                              };                                                                                    
3355                              resizeRunnable = (new Runnable() {                                                    
3356                                  public void run() {                                                               
3357                                      if (!isPageMoving()) {                                                        
3358                                          addResizeFrame.run();                                                     
3359                                      } else {                                                                      
3360                                          mDelayedResizeRunnable = addResizeFrame;                                  
3361                                      }                                                                             
3362                                  }                                                                                 
3363                              });                                                                                   
3364                          }                                                                                         
3365                      }                                                                                             
3366                                                                                                                    
3367                      LauncherModel.modifyItemInDatabase(mLauncher, info, container, screenId, lp.cellX,            
3368                              lp.cellY, item.spanX, item.spanY);                                                    
3369                  } else {                                                                                          
3370                      // If we can't find a drop location, we return the item to its original position              
3371                      CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams();                
3372                      mTargetCell[0] = lp.cellX;                                                                    
3373                      mTargetCell[1] = lp.cellY;                                                                    
3374                      CellLayout layout = (CellLayout) cell.getParent().getParent();                                
3375                      layout.markCellsAsOccupiedForView(cell);                                                      
3376                  }                                                                                                 
3377              }                                                                                                     
3378                                                                                                                    
3379              final CellLayout parent = (CellLayout) cell.getParent().getParent();                                  
3380              final Runnable finalResizeRunnable = resizeRunnable;                                                  
3381              // Prepare it to be animated into its new position                                                    
3382              // This must be called after the view has been re-parented                                            
3383              final Runnable onCompleteRunnable = new Runnable() {                                                  
3384                  @Override                                                                                         
3385                  public void run() {                                                                               
3386                      mAnimatingViewIntoPlace = false;                                                              
3387                      updateChildrenLayersEnabled(false);                                                           
3388                      if (finalResizeRunnable != null) {                                                            
3389                          finalResizeRunnable.run();                                                                
3390                      }                                                                                             
3391 -                    removeExtraEmptyScreen(true, null, 0, true);                                                  
3392                  }                                                                                                 
3393              };                                                                                                    
3394              mAnimatingViewIntoPlace = true;                                                                       
3395              if (d.dragView.hasDrawn()) {                                                                          
3396                  final ItemInfo info = (ItemInfo) cell.getTag();                                                   
3397                  if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET) {                            
3398                      int animationType = resizeOnDrop ? ANIMATE_INTO_POSITION_AND_RESIZE :                         
3399                              ANIMATE_INTO_POSITION_AND_DISAPPEAR;                                                  
3400                      animateWidgetDrop(info, parent, d.dragView,                                                   
3401                              onCompleteRunnable, animationType, cell, false);                                      
3402                  } else {                                                                                          
3403                      int duration = snapScreen < 0 ? -1 : ADJACENT_SCREEN_DROP_DURATION;                           
3404                      mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, cell, duration,                  
3405                              onCompleteRunnable, this);                                                            
3406                  }                                                                                                 
3407              } else {                                                                                              
3408                  d.deferDragViewCleanupPostAnimation = false;                                                      
3409                  cell.setVisibility(VISIBLE);                                                                      
3410              }                                                                                                     
3411              parent.onDropChild(cell);                                                                             
3412          }                                                                                                         
3413      }                                                                                                             
3414                                                                                                                    
3415      public void setFinalScrollForPageChange(int pageIndex) {                                                      
3416          CellLayout cl = (CellLayout) getChildAt(pageIndex);                                                       
3417          if (cl != null) {                                                                                         
3418              mSavedScrollX = getScrollX();                                                                         
3419              mSavedTranslationX = cl.getTranslationX();                                                            
3420              mSavedRotationY = cl.getRotationY();                                                                  
3421              final int newX = getScrollForPage(pageIndex);                                                         
3422              setScrollX(newX);                                                                                     
3423              cl.setTranslationX(0f);                                                                               
3424              cl.setRotationY(0f);                                                                                  
3425          }                                                                                                         
3426      }                                                                                                             
3427                                                                                                                    
3428      public void resetFinalScrollForPageChange(int pageIndex) {                                                    
3429          if (pageIndex >= 0) {                                                                                     
3430              CellLayout cl = (CellLayout) getChildAt(pageIndex);                                                   
3431              setScrollX(mSavedScrollX);                                                                            
3432              cl.setTranslationX(mSavedTranslationX);                                                               
3433              cl.setRotationY(mSavedRotationY);                                                                     
3434          }                                                                                                         
3435      }                                                                                                             
3436                                                                                                                    
3437      public void getViewLocationRelativeToSelf(View v, int[] location) {                                           
3438          getLocationInWindow(location);                                                                            
3439          int x = location[0];                                                                                      
3440          int y = location[1];                                                                                      
3441                                                                                                                    
3442          v.getLocationInWindow(location);                                                                          
3443          int vX = location[0];                                                                                     
3444          int vY = location[1];                                                                                     
3445                                                                                                                    
3446          location[0] = vX - x;                                                                                     
3447          location[1] = vY - y;                                                                                     
3448      }                                                                                                             
3449                                                                                                                    
3450      public void onDragEnter(DragObject d) {                                                                       
3451          mDragEnforcer.onDragEnter();                                                                              
3452          mCreateUserFolderOnDrop = false;                                                                          
3453          mAddToExistingFolderOnDrop = false;                                                                       
3454                                                                                                                    
3455          mDropToLayout = null;                                                                                     
3456          CellLayout layout = getCurrentDropLayout();                                                               
3457          setCurrentDropLayout(layout);                                                                             
3458          setCurrentDragOverlappingLayout(layout);                                                                  
3459                                                                                                                    
3460 -        // Because we don't have space in the Phone UI (the CellLayouts run to the edge) we                       
3461 -        // don't need to show the outlines                                                                        
3462 -        if (LauncherAppState.getInstance().isScreenLarge()) {                                                     
3463 -            showOutlines();                                                                                       
3464 +        if (!workspaceInModalState()) {                                                                           
3465 +            mLauncher.getDragLayer().showPageHints();                                                             
3466          }                                                                                                         
3467      }                                                                                                             
3468                                                                                                                    
3469      /** Return a rect that has the cellWidth/cellHeight (left, top), and                                          
3470       * widthGap/heightGap (right, bottom) */                                                                      
3471      static Rect getCellLayoutMetrics(Launcher launcher, int orientation) {                                        
3472          LauncherAppState app = LauncherAppState.getInstance();                                                    
3473          DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                             
3474                                                                                                                    
3475 -        Resources res = launcher.getResources();                                                                  
3476          Display display = launcher.getWindowManager().getDefaultDisplay();                                        
3477          Point smallestSize = new Point();                                                                         
3478          Point largestSize = new Point();                                                                          
3479          display.getCurrentSizeRange(smallestSize, largestSize);                                                   
3480          int countX = (int) grid.numColumns;                                                                       
3481          int countY = (int) grid.numRows;                                                                          
3482          if (orientation == CellLayout.LANDSCAPE) {                                                                
3483              if (mLandscapeCellLayoutMetrics == null) {                                                            
3484                  Rect padding = grid.getWorkspacePadding(CellLayout.LANDSCAPE);                                    
3485                  int width = largestSize.x - padding.left - padding.right;                                         
3486                  int height = smallestSize.y - padding.top - padding.bottom;                                       
3487                  mLandscapeCellLayoutMetrics = new Rect();                                                         
3488                  mLandscapeCellLayoutMetrics.set(                                                                  
3489                          grid.calculateCellWidth(width, countX),                                                   
3490                          grid.calculateCellHeight(height, countY), 0, 0);                                          
3491              }                                                                                                     
3492              return mLandscapeCellLayoutMetrics;                                                                   
3493          } else if (orientation == CellLayout.PORTRAIT) {                                                          
3494              if (mPortraitCellLayoutMetrics == null) {                                                             
3495                  Rect padding = grid.getWorkspacePadding(CellLayout.PORTRAIT);                                     
3496                  int width = smallestSize.x - padding.left - padding.right;                                        
3497                  int height = largestSize.y - padding.top - padding.bottom;                                        
3498                  mPortraitCellLayoutMetrics = new Rect();                                                          
3499                  mPortraitCellLayoutMetrics.set(                                                                   
3500                          grid.calculateCellWidth(width, countX),                                                   
3501                          grid.calculateCellHeight(height, countY), 0, 0);                                          
3502              }                                                                                                     
3503              return mPortraitCellLayoutMetrics;                                                                    
3504          }                                                                                                         
3505          return null;                                                                                              
3506      }                                                                                                             
3507                                                                                                                    
3508      public void onDragExit(DragObject d) {                                                                        
3509          mDragEnforcer.onDragExit();                                                                               
3510                                                                                                                    
3511          // Here we store the final page that will be dropped to, if the workspace in fact                         
3512          // receives the drop                                                                                      
3513          if (mInScrollArea) {                                                                                      
3514              if (isPageMoving()) {                                                                                 
3515                  // If the user drops while the page is scrolling, we should use that page as the                  
3516                  // destination instead of the page that is being hovered over.                                    
3517                  mDropToLayout = (CellLayout) getPageAt(getNextPage());                                            
3518              } else {                                                                                              
3519                  mDropToLayout = mDragOverlappingLayout;                                                           
3520              }                                                                                                     
3521          } else {                                                                                                  
3522              mDropToLayout = mDragTargetLayout;                                                                    
3523          }                                                                                                         
3524                                                                                                                    
3525          if (mDragMode == DRAG_MODE_CREATE_FOLDER) {                                                               
3526              mCreateUserFolderOnDrop = true;                                                                       
3527          } else if (mDragMode == DRAG_MODE_ADD_TO_FOLDER) {                                                        
3528              mAddToExistingFolderOnDrop = true;                                                                    
3529          }                                                                                                         
3530                                                                                                                    
3531          // Reset the scroll area and previous drag target                                                         
3532          onResetScrollArea();                                                                                      
3533          setCurrentDropLayout(null);                                                                               
3534          setCurrentDragOverlappingLayout(null);                                                                    
3535                                                                                                                    
3536          mSpringLoadedDragController.cancel();                                                                     
3537                                                                                                                    
3538          if (!mIsPageMoving) {                                                                                     
3539              hideOutlines();                                                                                       
3540          }                                                                                                         
3541 +        mLauncher.getDragLayer().hidePageHints();                                                                 
3542      }                                                                                                             
3543                                                                                                                    
3544      void setCurrentDropLayout(CellLayout layout) {                                                                
3545          if (mDragTargetLayout != null) {                                                                          
3546              mDragTargetLayout.revertTempState();                                                                  
3547              mDragTargetLayout.onDragExit();                                                                       
3548          }                                                                                                         
3549          mDragTargetLayout = layout;                                                                               
3550          if (mDragTargetLayout != null) {                                                                          
3551              mDragTargetLayout.onDragEnter();                                                                      
3552          }                                                                                                         
3553          cleanupReorder(true);                                                                                     
3554          cleanupFolderCreation();                                                                                  
3555          setCurrentDropOverCell(-1, -1);                                                                           
3556      }                                                                                                             
3557                                                                                                                    
3558      void setCurrentDragOverlappingLayout(CellLayout layout) {                                                     
3559          if (mDragOverlappingLayout != null) {                                                                     
3560              mDragOverlappingLayout.setIsDragOverlapping(false);                                                   
3561          }                                                                                                         
3562          mDragOverlappingLayout = layout;                                                                          
3563          if (mDragOverlappingLayout != null) {                                                                     
3564              mDragOverlappingLayout.setIsDragOverlapping(true);                                                    
3565          }                                                                                                         
3566          invalidate();                                                                                             
3567      }                                                                                                             
3568                                                                                                                    
3569      void setCurrentDropOverCell(int x, int y) {                                                                   
3570          if (x != mDragOverX || y != mDragOverY) {                                                                 
3571              mDragOverX = x;                                                                                       
3572              mDragOverY = y;                                                                                       
3573              setDragMode(DRAG_MODE_NONE);                                                                          
3574          }                                                                                                         
3575      }                                                                                                             
3576                                                                                                                    
3577      void setDragMode(int dragMode) {                                                                              
3578          if (dragMode != mDragMode) {                                                                              
3579              if (dragMode == DRAG_MODE_NONE) {                                                                     
3580                  cleanupAddToFolder();                                                                             
3581                  // We don't want to cancel the re-order alarm every time the target cell changes                  
3582                  // as this feels to slow / unresponsive.                                                          
3583                  cleanupReorder(false);                                                                            
3584                  cleanupFolderCreation();                                                                          
3585              } else if (dragMode == DRAG_MODE_ADD_TO_FOLDER) {                                                     
3586                  cleanupReorder(true);                                                                             
3587                  cleanupFolderCreation();                                                                          
3588              } else if (dragMode == DRAG_MODE_CREATE_FOLDER) {                                                     
3589                  cleanupAddToFolder();                                                                             
3590                  cleanupReorder(true);                                                                             
3591              } else if (dragMode == DRAG_MODE_REORDER) {                                                           
3592                  cleanupAddToFolder();                                                                             
3593                  cleanupFolderCreation();                                                                          
3594              }                                                                                                     
3595              mDragMode = dragMode;                                                                                 
3596          }                                                                                                         
3597      }                                                                                                             
3598                                                                                                                    
3599      private void cleanupFolderCreation() {                                                                        
3600          if (mDragFolderRingAnimator != null) {                                                                    
3601              mDragFolderRingAnimator.animateToNaturalState();                                                      
3602              mDragFolderRingAnimator = null;                                                                       
3603          }                                                                                                         
3604          mFolderCreationAlarm.setOnAlarmListener(null);                                                            
3605          mFolderCreationAlarm.cancelAlarm();                                                                       
3606      }                                                                                                             
3607                                                                                                                    
3608      private void cleanupAddToFolder() {                                                                           
3609          if (mDragOverFolderIcon != null) {                                                                        
3610              mDragOverFolderIcon.onDragExit(null);                                                                 
3611              mDragOverFolderIcon = null;                                                                           
3612          }                                                                                                         
3613      }                                                                                                             
3614                                                                                                                    
3615      private void cleanupReorder(boolean cancelAlarm) {                                                            
3616          // Any pending reorders are canceled                                                                      
3617          if (cancelAlarm) {                                                                                        
3618              mReorderAlarm.cancelAlarm();                                                                          
3619          }                                                                                                         
3620          mLastReorderX = -1;                                                                                       
3621          mLastReorderY = -1;                                                                                       
3622      }                                                                                                             
3623                                                                                                                    
3624     /*                                                                                                             
3625      *                                                                                                             
3626      * Convert the 2D coordinate xy from the parent View's coordinate space to this CellLayout's                   
3627      * coordinate space. The argument xy is modified with the return result.                                       
3628      *                                                                                                             
3629      * if cachedInverseMatrix is not null, this method will just use that matrix instead of                        
3630      * computing it itself; we use this to avoid redundant matrix inversions in                                    
3631      * findMatchingPageForDragOver                                                                                 
3632      *                                                                                                             
3633      */                                                                                                            
3634     void mapPointFromSelfToChild(View v, float[] xy, Matrix cachedInverseMatrix) {                                 
3635         xy[0] = xy[0] - v.getLeft();                                                                               
3636         xy[1] = xy[1] - v.getTop();                                                                                
3637     }                                                                                                              
3638                                                                                                                    
3639     boolean isPointInSelfOverHotseat(int x, int y, Rect r) {                                                       
3640         if (r == null) {                                                                                           
3641             r = new Rect();                                                                                        
3642         }                                                                                                          
3643         mTempPt[0] = x;                                                                                            
3644         mTempPt[1] = y;                                                                                            
3645         mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempPt, true);                            
3646                                                                                                                    
3647         LauncherAppState app = LauncherAppState.getInstance();                                                     
3648         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                              
3649         r = grid.getHotseatRect();                                                                                 
3650         if (r.contains(mTempPt[0], mTempPt[1])) {                                                                  
3651             return true;                                                                                           
3652         }                                                                                                          
3653         return false;                                                                                              
3654     }                                                                                                              
3655                                                                                                                    
3656     void mapPointFromSelfToHotseatLayout(Hotseat hotseat, float[] xy) {                                            
3657         mTempPt[0] = (int) xy[0];                                                                                  
3658         mTempPt[1] = (int) xy[1];                                                                                  
3659         mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(this, mTempPt, true);                            
3660         mLauncher.getDragLayer().mapCoordInSelfToDescendent(hotseat.getLayout(), mTempPt);                         
3661                                                                                                                    
3662         xy[0] = mTempPt[0];                                                                                        
3663         xy[1] = mTempPt[1];                                                                                        
3664     }                                                                                                              
3665                                                                                                                    
3666     /*                                                                                                             
3667      *                                                                                                             
3668      * Convert the 2D coordinate xy from this CellLayout's coordinate space to                                     
3669      * the parent View's coordinate space. The argument xy is modified with the return result.                     
3670      *                                                                                                             
3671      */                                                                                                            
3672     void mapPointFromChildToSelf(View v, float[] xy) {                                                             
3673         xy[0] += v.getLeft();                                                                                      
3674         xy[1] += v.getTop();                                                                                       
3675     }                                                                                                              
3676                                                                                                                    
3677     static private float squaredDistance(float[] point1, float[] point2) {                                         
3678          float distanceX = point1[0] - point2[0];                                                                  
3679          float distanceY = point2[1] - point2[1];                                                                  
3680          return distanceX * distanceX + distanceY * distanceY;                                                     
3681     }                                                                                                              
3682                                                                                                                    
3683      /*                                                                                                            
3684       *                                                                                                            
3685       * This method returns the CellLayout that is currently being dragged to. In order to drag                    
3686       * to a CellLayout, either the touch point must be directly over the CellLayout, or as a second               
3687       * strategy, we see if the dragView is overlapping any CellLayout and choose the closest one                  
3688       *                                                                                                            
3689       * Return null if no CellLayout is currently being dragged over                                               
3690       *                                                                                                            
3691       */                                                                                                           
3692      private CellLayout findMatchingPageForDragOver(                                                               
3693              DragView dragView, float originX, float originY, boolean exact) {                                     
3694          // We loop through all the screens (ie CellLayouts) and see which ones overlap                            
3695          // with the item being dragged and then choose the one that's closest to the touch point                  
3696          final int screenCount = getChildCount();                                                                  
3697          CellLayout bestMatchingScreen = null;                                                                     
3698          float smallestDistSoFar = Float.MAX_VALUE;                                                                
3699                                                                                                                    
3700          for (int i = 0; i < screenCount; i++) {                                                                   
3701              // The custom content screen is not a valid drag over option                                          
3702              if (mScreenOrder.get(i) == CUSTOM_CONTENT_SCREEN_ID) {                                                
3703                  continue;                                                                                         
3704              }                                                                                                     
3705                                                                                                                    
3706              CellLayout cl = (CellLayout) getChildAt(i);                                                           
3707                                                                                                                    
3708              final float[] touchXy = {originX, originY};                                                           
3709              // Transform the touch coordinates to the CellLayout's local coordinates                              
3710              // If the touch point is within the bounds of the cell layout, we can return immediately              
3711              cl.getMatrix().invert(mTempInverseMatrix);                                                            
3712              mapPointFromSelfToChild(cl, touchXy, mTempInverseMatrix);                                             
3713                                                                                                                    
3714              if (touchXy[0] >= 0 && touchXy[0] <= cl.getWidth() &&                                                 
3715                      touchXy[1] >= 0 && touchXy[1] <= cl.getHeight()) {                                            
3716                  return cl;                                                                                        
3717              }                                                                                                     
3718                                                                                                                    
3719              if (!exact) {                                                                                         
3720                  // Get the center of the cell layout in screen coordinates                                        
3721                  final float[] cellLayoutCenter = mTempCellLayoutCenterCoordinates;                                
3722                  cellLayoutCenter[0] = cl.getWidth()/2;                                                            
3723                  cellLayoutCenter[1] = cl.getHeight()/2;                                                           
3724                  mapPointFromChildToSelf(cl, cellLayoutCenter);                                                    
3725                                                                                                                    
3726                  touchXy[0] = originX;                                                                             
3727                  touchXy[1] = originY;                                                                             
3728                                                                                                                    
3729                  // Calculate the distance between the center of the CellLayout                                    
3730                  // and the touch point                                                                            
3731                  float dist = squaredDistance(touchXy, cellLayoutCenter);                                          
3732                                                                                                                    
3733                  if (dist < smallestDistSoFar) {                                                                   
3734                      smallestDistSoFar = dist;                                                                     
3735                      bestMatchingScreen = cl;                                                                      
3736                  }                                                                                                 
3737              }                                                                                                     
3738          }                                                                                                         
3739          return bestMatchingScreen;                                                                                
3740      }                                                                                                             
3741                                                                                                                    
3742      // This is used to compute the visual center of the dragView. This point is then                              
3743      // used to visualize drop locations and determine where to drop an item. The idea is that                     
3744      // the visual center represents the user's interpretation of where the item is, and hence                     
3745      // is the appropriate point to use when determining drop location.                                            
3746      private float[] getDragViewVisualCenter(int x, int y, int xOffset, int yOffset,                               
3747              DragView dragView, float[] recycle) {                                                                 
3748          float res[];                                                                                              
3749          if (recycle == null) {                                                                                    
3750              res = new float[2];                                                                                   
3751          } else {                                                                                                  
3752              res = recycle;                                                                                        
3753          }                                                                                                         
3754                                                                                                                    
3755          // First off, the drag view has been shifted in a way that is not represented in the                      
3756          // x and y values or the x/yOffsets. Here we account for that shift.                                      
3757          x += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetX);                                       
3758          y += getResources().getDimensionPixelSize(R.dimen.dragViewOffsetY);                                       
3759                                                                                                                    
3760          // These represent the visual top and left of drag view if a dragRect was provided.                       
3761          // If a dragRect was not provided, then they correspond to the actual view left and                       
3762          // top, as the dragRect is in that case taken to be the entire dragView.                                  
3763          // R.dimen.dragViewOffsetY.                                                                               
3764          int left = x - xOffset;                                                                                   
3765          int top = y - yOffset;                                                                                    
3766                                                                                                                    
3767          // In order to find the visual center, we shift by half the dragRect                                      
3768          res[0] = left + dragView.getDragRegion().width() / 2;                                                     
3769          res[1] = top + dragView.getDragRegion().height() / 2;                                                     
3770                                                                                                                    
3771          return res;                                                                                               
3772      }                                                                                                             
3773                                                                                                                    
3774      private boolean isDragWidget(DragObject d) {                                                                  
3775          return (d.dragInfo instanceof LauncherAppWidgetInfo ||                                                    
3776                  d.dragInfo instanceof PendingAddWidgetInfo);                                                      
3777      }                                                                                                             
3778      private boolean isExternalDragWidget(DragObject d) {                                                          
3779          return d.dragSource != this && isDragWidget(d);                                                           
3780      }                                                                                                             
3781                                                                                                                    
3782      public void onDragOver(DragObject d) {                                                                        
3783          // Skip drag over events while we are dragging over side pages                                            
3784 -        if (mInScrollArea || mIsSwitchingState || mState == State.SMALL) return;                                  
3785 +        if (mInScrollArea || !transitionStateShouldAllowDrop()) return;                                           
3786                                                                                                                    
3787          Rect r = new Rect();                                                                                      
3788          CellLayout layout = null;                                                                                 
3789          ItemInfo item = (ItemInfo) d.dragInfo;                                                                    
3790 +        if (item == null) {                                                                                       
3791 +            if (LauncherAppState.isDogfoodBuild()) {                                                              
3792 +                throw new NullPointerException("DragObject has null info");                                       
3793 +            }                                                                                                     
3794 +            return;                                                                                               
3795 +        }                                                                                                         
3796                                                                                                                    
3797          // Ensure that we have proper spans for the item that we are dropping                                     
3798          if (item.spanX < 0 || item.spanY < 0) throw new RuntimeException("Improper spans found");                 
3799          mDragViewVisualCenter = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset,                           
3800              d.dragView, mDragViewVisualCenter);                                                                   
3801                                                                                                                    
3802          final View child = (mDragInfo == null) ? null : mDragInfo.cell;                                           
3803          // Identify whether we have dragged over a side page                                                      
3804 -        if (isSmall()) {                                                                                          
3805 +        if (workspaceInModalState()) {                                                                            
3806              if (mLauncher.getHotseat() != null && !isExternalDragWidget(d)) {                                     
3807                  if (isPointInSelfOverHotseat(d.x, d.y, r)) {                                                      
3808                      layout = mLauncher.getHotseat().getLayout();                                                  
3809                  }                                                                                                 
3810              }                                                                                                     
3811              if (layout == null) {                                                                                 
3812                  layout = findMatchingPageForDragOver(d.dragView, d.x, d.y, false);                                
3813              }                                                                                                     
3814              if (layout != mDragTargetLayout) {                                                                    
3815                  setCurrentDropLayout(layout);                                                                     
3816                  setCurrentDragOverlappingLayout(layout);                                                          
3817                                                                                                                    
3818                  boolean isInSpringLoadedMode = (mState == State.SPRING_LOADED);                                   
3819                  if (isInSpringLoadedMode) {                                                                       
3820                      if (mLauncher.isHotseatLayout(layout)) {                                                      
3821                          mSpringLoadedDragController.cancel();                                                     
3822                      } else {                                                                                      
3823                          mSpringLoadedDragController.setAlarm(mDragTargetLayout);                                  
3824                      }                                                                                             
3825                  }                                                                                                 
3826              }                                                                                                     
3827          } else {                                                                                                  
3828              // Test to see if we are over the hotseat otherwise just use the current page                         
3829              if (mLauncher.getHotseat() != null && !isDragWidget(d)) {                                             
3830                  if (isPointInSelfOverHotseat(d.x, d.y, r)) {                                                      
3831                      layout = mLauncher.getHotseat().getLayout();                                                  
3832                  }                                                                                                 
3833              }                                                                                                     
3834              if (layout == null) {                                                                                 
3835                  layout = getCurrentDropLayout();                                                                  
3836              }                                                                                                     
3837              if (layout != mDragTargetLayout) {                                                                    
3838                  setCurrentDropLayout(layout);                                                                     
3839                  setCurrentDragOverlappingLayout(layout);                                                          
3840              }                                                                                                     
3841          }                                                                                                         
3842                                                                                                                    
3843          // Handle the drag over                                                                                   
3844          if (mDragTargetLayout != null) {                                                                          
3845              // We want the point to be mapped to the dragTarget.                                                  
3846              if (mLauncher.isHotseatLayout(mDragTargetLayout)) {                                                   
3847                  mapPointFromSelfToHotseatLayout(mLauncher.getHotseat(), mDragViewVisualCenter);                   
3848              } else {                                                                                              
3849                  mapPointFromSelfToChild(mDragTargetLayout, mDragViewVisualCenter, null);                          
3850              }                                                                                                     
3851                                                                                                                    
3852              ItemInfo info = (ItemInfo) d.dragInfo;                                                                
3853                                                                                                                    
3854              int minSpanX = item.spanX;                                                                            
3855              int minSpanY = item.spanY;                                                                            
3856              if (item.minSpanX > 0 && item.minSpanY > 0) {                                                         
3857                  minSpanX = item.minSpanX;                                                                         
3858                  minSpanY = item.minSpanY;                                                                         
3859              }                                                                                                     
3860                                                                                                                    
3861              mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],                                         
3862                      (int) mDragViewVisualCenter[1], minSpanX, minSpanY,                                           
3863                      mDragTargetLayout, mTargetCell);                                                              
3864              int reorderX = mTargetCell[0];                                                                        
3865              int reorderY = mTargetCell[1];                                                                        
3866                                                                                                                    
3867              setCurrentDropOverCell(mTargetCell[0], mTargetCell[1]);                                               
3868                                                                                                                    
3869              float targetCellDistance = mDragTargetLayout.getDistanceFromCell(                                     
3870                      mDragViewVisualCenter[0], mDragViewVisualCenter[1], mTargetCell);                             
3871                                                                                                                    
3872              final View dragOverView = mDragTargetLayout.getChildAt(mTargetCell[0],                                
3873                      mTargetCell[1]);                                                                              
3874                                                                                                                    
3875              manageFolderFeedback(info, mDragTargetLayout, mTargetCell,                                            
3876                      targetCellDistance, dragOverView);                                                            
3877                                                                                                                    
3878              boolean nearestDropOccupied = mDragTargetLayout.isNearestDropLocationOccupied((int)                   
3879                      mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1], item.spanX,                         
3880                      item.spanY, child, mTargetCell);                                                              
3881                                                                                                                    
3882              if (!nearestDropOccupied) {                                                                           
3883                  mDragTargetLayout.visualizeDropLocation(child, mDragOutline,                                      
3884                          (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1],                           
3885                          mTargetCell[0], mTargetCell[1], item.spanX, item.spanY, false,                            
3886                          d.dragView.getDragVisualizeOffset(), d.dragView.getDragRegion());                         
3887              } else if ((mDragMode == DRAG_MODE_NONE || mDragMode == DRAG_MODE_REORDER)                            
3888                      && !mReorderAlarm.alarmPending() && (mLastReorderX != reorderX ||                             
3889                      mLastReorderY != reorderY)) {                                                                 
3890                                                                                                                    
3891                  int[] resultSpan = new int[2];                                                                    
3892                  mDragTargetLayout.performReorder((int) mDragViewVisualCenter[0],                                  
3893                          (int) mDragViewVisualCenter[1], minSpanX, minSpanY, item.spanX, item.spanY,               
3894                          child, mTargetCell, resultSpan, CellLayout.MODE_SHOW_REORDER_HINT);                       
3895                                                                                                                    
3896                  // Otherwise, if we aren't adding to or creating a folder and there's no pending                  
3897                  // reorder, then we schedule a reorder                                                            
3898                  ReorderAlarmListener listener = new ReorderAlarmListener(mDragViewVisualCenter,                   
3899                          minSpanX, minSpanY, item.spanX, item.spanY, d.dragView, child);                           
3900                  mReorderAlarm.setOnAlarmListener(listener);                                                       
3901                  mReorderAlarm.setAlarm(REORDER_TIMEOUT);                                                          
3902              }                                                                                                     
3903                                                                                                                    
3904              if (mDragMode == DRAG_MODE_CREATE_FOLDER || mDragMode == DRAG_MODE_ADD_TO_FOLDER ||                   
3905                      !nearestDropOccupied) {                                                                       
3906                  if (mDragTargetLayout != null) {                                                                  
3907                      mDragTargetLayout.revertTempState();                                                          
3908                  }                                                                                                 
3909              }                                                                                                     
3910          }                                                                                                         
3911      }                                                                                                             
3912                                                                                                                    
3913      private void manageFolderFeedback(ItemInfo info, CellLayout targetLayout,                                     
3914              int[] targetCell, float distance, View dragOverView) {                                                
3915          boolean userFolderPending = willCreateUserFolder(info, targetLayout, targetCell, distance,                
3916                  false);                                                                                           
3917                                                                                                                    
3918          if (mDragMode == DRAG_MODE_NONE && userFolderPending &&                                                   
3919                  !mFolderCreationAlarm.alarmPending()) {                                                           
3920              mFolderCreationAlarm.setOnAlarmListener(new                                                           
3921                      FolderCreationAlarmListener(targetLayout, targetCell[0], targetCell[1]));                     
3922              mFolderCreationAlarm.setAlarm(FOLDER_CREATION_TIMEOUT);                                               
3923              return;                                                                                               
3924          }                                                                                                         
3925                                                                                                                    
3926          boolean willAddToFolder =                                                                                 
3927                  willAddToExistingUserFolder(info, targetLayout, targetCell, distance);                            
3928                                                                                                                    
3929          if (willAddToFolder && mDragMode == DRAG_MODE_NONE) {                                                     
3930              mDragOverFolderIcon = ((FolderIcon) dragOverView);                                                    
3931              mDragOverFolderIcon.onDragEnter(info);                                                                
3932              if (targetLayout != null) {                                                                           
3933                  targetLayout.clearDragOutlines();                                                                 
3934              }                                                                                                     
3935              setDragMode(DRAG_MODE_ADD_TO_FOLDER);                                                                 
3936              return;                                                                                               
3937          }                                                                                                         
3938                                                                                                                    
3939          if (mDragMode == DRAG_MODE_ADD_TO_FOLDER && !willAddToFolder) {                                           
3940              setDragMode(DRAG_MODE_NONE);                                                                          
3941          }                                                                                                         
3942          if (mDragMode == DRAG_MODE_CREATE_FOLDER && !userFolderPending) {                                         
3943              setDragMode(DRAG_MODE_NONE);                                                                          
3944          }                                                                                                         
3945                                                                                                                    
3946          return;                                                                                                   
3947      }                                                                                                             
3948                                                                                                                    
3949      class FolderCreationAlarmListener implements OnAlarmListener {                                                
3950          CellLayout layout;                                                                                        
3951          int cellX;                                                                                                
3952          int cellY;                                                                                                
3953                                                                                                                    
3954          public FolderCreationAlarmListener(CellLayout layout, int cellX, int cellY) {                             
3955              this.layout = layout;                                                                                 
3956              this.cellX = cellX;                                                                                   
3957              this.cellY = cellY;                                                                                   
3958          }                                                                                                         
3959                                                                                                                    
3960          public void onAlarm(Alarm alarm) {                                                                        
3961              if (mDragFolderRingAnimator != null) {                                                                
3962                  // This shouldn't happen ever, but just in case, make sure we clean up the mess.                  
3963                  mDragFolderRingAnimator.animateToNaturalState();                                                  
3964              }                                                                                                     
3965              mDragFolderRingAnimator = new FolderRingAnimator(mLauncher, null);                                    
3966              mDragFolderRingAnimator.setCell(cellX, cellY);                                                        
3967              mDragFolderRingAnimator.setCellLayout(layout);                                                        
3968              mDragFolderRingAnimator.animateToAcceptState();                                                       
3969              layout.showFolderAccept(mDragFolderRingAnimator);                                                     
3970              layout.clearDragOutlines();                                                                           
3971              setDragMode(DRAG_MODE_CREATE_FOLDER);                                                                 
3972          }                                                                                                         
3973      }                                                                                                             
3974                                                                                                                    
3975      class ReorderAlarmListener implements OnAlarmListener {                                                       
3976          float[] dragViewCenter;                                                                                   
3977          int minSpanX, minSpanY, spanX, spanY;                                                                     
3978          DragView dragView;                                                                                        
3979          View child;                                                                                               
3980                                                                                                                    
3981          public ReorderAlarmListener(float[] dragViewCenter, int minSpanX, int minSpanY, int spanX,                
3982                  int spanY, DragView dragView, View child) {                                                       
3983              this.dragViewCenter = dragViewCenter;                                                                 
3984              this.minSpanX = minSpanX;                                                                             
3985              this.minSpanY = minSpanY;                                                                             
3986              this.spanX = spanX;                                                                                   
3987              this.spanY = spanY;                                                                                   
3988              this.child = child;                                                                                   
3989              this.dragView = dragView;                                                                             
3990          }                                                                                                         
3991                                                                                                                    
3992          public void onAlarm(Alarm alarm) {                                                                        
3993              int[] resultSpan = new int[2];                                                                        
3994              mTargetCell = findNearestArea((int) mDragViewVisualCenter[0],                                         
3995                      (int) mDragViewVisualCenter[1], minSpanX, minSpanY, mDragTargetLayout,                        
3996                      mTargetCell);                                                                                 
3997              mLastReorderX = mTargetCell[0];                                                                       
3998              mLastReorderY = mTargetCell[1];                                                                       
3999                                                                                                                    
4000              mTargetCell = mDragTargetLayout.performReorder((int) mDragViewVisualCenter[0],                        
4001                  (int) mDragViewVisualCenter[1], minSpanX, minSpanY, spanX, spanY,                                 
4002                  child, mTargetCell, resultSpan, CellLayout.MODE_DRAG_OVER);                                       
4003                                                                                                                    
4004              if (mTargetCell[0] < 0 || mTargetCell[1] < 0) {                                                       
4005                  mDragTargetLayout.revertTempState();                                                              
4006              } else {                                                                                              
4007                  setDragMode(DRAG_MODE_REORDER);                                                                   
4008              }                                                                                                     
4009                                                                                                                    
4010              boolean resize = resultSpan[0] != spanX || resultSpan[1] != spanY;                                    
4011              mDragTargetLayout.visualizeDropLocation(child, mDragOutline,                                          
4012                  (int) mDragViewVisualCenter[0], (int) mDragViewVisualCenter[1],                                   
4013                  mTargetCell[0], mTargetCell[1], resultSpan[0], resultSpan[1], resize,                             
4014                  dragView.getDragVisualizeOffset(), dragView.getDragRegion());                                     
4015          }                                                                                                         
4016      }                                                                                                             
4017                                                                                                                    
4018      @Override                                                                                                     
4019      public void getHitRectRelativeToDragLayer(Rect outRect) {                                                     
4020          // We want the workspace to have the whole area of the display (it will find the correct                  
4021          // cell layout to drop to in the existing drag/drop logic.                                                
4022          mLauncher.getDragLayer().getDescendantRectRelativeToSelf(this, outRect);                                  
4023      }                                                                                                             
4024                                                                                                                    
4025      /**                                                                                                           
4026       * Add the item specified by dragInfo to the given layout.                                                    
4027       * @return true if successful                                                                                 
4028       */                                                                                                           
4029      public boolean addExternalItemToScreen(ItemInfo dragInfo, CellLayout layout) {                                
4030          if (layout.findCellForSpan(mTempEstimate, dragInfo.spanX, dragInfo.spanY)) {                              
4031              onDropExternal(dragInfo.dropPos, (ItemInfo) dragInfo, (CellLayout) layout, false);                    
4032              return true;                                                                                          
4033          }                                                                                                         
4034          mLauncher.showOutOfSpaceMessage(mLauncher.isHotseatLayout(layout));                                       
4035          return false;                                                                                             
4036      }                                                                                                             
4037                                                                                                                    
4038      private void onDropExternal(int[] touchXY, Object dragInfo,                                                   
4039              CellLayout cellLayout, boolean insertAtFirst) {                                                       
4040          onDropExternal(touchXY, dragInfo, cellLayout, insertAtFirst, null);                                       
4041      }                                                                                                             
4042                                                                                                                    
4043      /**                                                                                                           
4044       * Drop an item that didn't originate on one of the workspace screens.                                        
4045       * It may have come from Launcher (e.g. from all apps or customize), or it may have                           
4046       * come from another app altogether.                                                                          
4047       *                                                                                                            
4048       * NOTE: This can also be called when we are outside of a drag event, when we want                            
4049       * to add an item to one of the workspace screens.                                                            
4050       */                                                                                                           
4051      private void onDropExternal(final int[] touchXY, final Object dragInfo,                                       
4052              final CellLayout cellLayout, boolean insertAtFirst, DragObject d) {                                   
4053          final Runnable exitSpringLoadedRunnable = new Runnable() {                                                
4054              @Override                                                                                             
4055              public void run() {                                                                                   
4056 -                removeExtraEmptyScreen(false, new Runnable() {                                                    
4057 -                    @Override                                                                                     
4058 -                    public void run() {                                                                           
4059 -                        mLauncher.exitSpringLoadedDragModeDelayed(true,                                           
4060 -                                Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);                             
4061 -                    }                                                                                             
4062 -                });                                                                                               
4063 +                mLauncher.exitSpringLoadedDragModeDelayed(true,                                                   
4064 +                        Launcher.EXIT_SPRINGLOADED_MODE_SHORT_TIMEOUT, null);                                     
4065              }                                                                                                     
4066          };                                                                                                        
4067                                                                                                                    
4068          ItemInfo info = (ItemInfo) dragInfo;                                                                      
4069          int spanX = info.spanX;                                                                                   
4070          int spanY = info.spanY;                                                                                   
4071          if (mDragInfo != null) {                                                                                  
4072              spanX = mDragInfo.spanX;                                                                              
4073              spanY = mDragInfo.spanY;                                                                              
4074          }                                                                                                         
4075                                                                                                                    
4076          final long container = mLauncher.isHotseatLayout(cellLayout) ?                                            
4077                  LauncherSettings.Favorites.CONTAINER_HOTSEAT :                                                    
4078                      LauncherSettings.Favorites.CONTAINER_DESKTOP;                                                 
4079          final long screenId = getIdForScreen(cellLayout);                                                         
4080          if (!mLauncher.isHotseatLayout(cellLayout)                                                                
4081                  && screenId != getScreenIdForPageIndex(mCurrentPage)                                              
4082                  && mState != State.SPRING_LOADED) {                                                               
4083              snapToScreenId(screenId, null);                                                                       
4084          }                                                                                                         
4085                                                                                                                    
4086          if (info instanceof PendingAddItemInfo) {                                                                 
4087              final PendingAddItemInfo pendingInfo = (PendingAddItemInfo) dragInfo;                                 
4088                                                                                                                    
4089              boolean findNearestVacantCell = true;                                                                 
4090              if (pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {                          
4091                  mTargetCell = findNearestArea((int) touchXY[0], (int) touchXY[1], spanX, spanY,                   
4092                          cellLayout, mTargetCell);                                                                 
4093                  float distance = cellLayout.getDistanceFromCell(mDragViewVisualCenter[0],                         
4094                          mDragViewVisualCenter[1], mTargetCell);                                                   
4095                  if (willCreateUserFolder((ItemInfo) d.dragInfo, cellLayout, mTargetCell,                          
4096                          distance, true) || willAddToExistingUserFolder((ItemInfo) d.dragInfo,                     
4097                                  cellLayout, mTargetCell, distance)) {                                             
4098                      findNearestVacantCell = false;                                                                
4099                  }                                                                                                 
4100              }                                                                                                     
4101                                                                                                                    
4102              final ItemInfo item = (ItemInfo) d.dragInfo;                                                          
4103              boolean updateWidgetSize = false;                                                                     
4104              if (findNearestVacantCell) {                                                                          
4105                  int minSpanX = item.spanX;                                                                        
4106                  int minSpanY = item.spanY;                                                                        
4107                  if (item.minSpanX > 0 && item.minSpanY > 0) {                                                     
4108                      minSpanX = item.minSpanX;                                                                     
4109                      minSpanY = item.minSpanY;                                                                     
4110                  }                                                                                                 
4111                  int[] resultSpan = new int[2];                                                                    
4112                  mTargetCell = cellLayout.performReorder((int) mDragViewVisualCenter[0],                           
4113                          (int) mDragViewVisualCenter[1], minSpanX, minSpanY, info.spanX, info.spanY,               
4114                          null, mTargetCell, resultSpan, CellLayout.MODE_ON_DROP_EXTERNAL);                         
4115                                                                                                                    
4116                  if (resultSpan[0] != item.spanX || resultSpan[1] != item.spanY) {                                 
4117                      updateWidgetSize = true;                                                                      
4118                  }                                                                                                 
4119                  item.spanX = resultSpan[0];                                                                       
4120                  item.spanY = resultSpan[1];                                                                       
4121              }                                                                                                     
4122                                                                                                                    
4123              Runnable onAnimationCompleteRunnable = new Runnable() {                                               
4124                  @Override                                                                                         
4125                  public void run() {                                                                               
4126 +                    // Normally removeExtraEmptyScreen is called in Workspace#onDragEnd, but when                 
4127 +                    // adding an item that may not be dropped right away (due to a config activity)               
4128 +                    // we defer the removal until the activity returns.                                           
4129 +                    deferRemoveExtraEmptyScreen();                                                                
4130 +                                                                                                                  
4131                      // When dragging and dropping from customization tray, we deal with creating                  
4132                      // widgets/shortcuts/folders in a slightly different way                                      
4133                      switch (pendingInfo.itemType) {                                                               
4134                      case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                                          
4135                          int span[] = new int[2];                                                                  
4136                          span[0] = item.spanX;                                                                     
4137                          span[1] = item.spanY;                                                                     
4138                          mLauncher.addAppWidgetFromDrop((PendingAddWidgetInfo) pendingInfo,                        
4139                                  container, screenId, mTargetCell, span, null);                                    
4140                          break;                                                                                    
4141                      case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                           
4142                          mLauncher.processShortcutFromDrop(pendingInfo.componentName,                              
4143                                  container, screenId, mTargetCell, null);                                          
4144                          break;                                                                                    
4145                      default:                                                                                      
4146                          throw new IllegalStateException("Unknown item type: " +                                   
4147                                  pendingInfo.itemType);                                                            
4148                      }                                                                                             
4149                  }                                                                                                 
4150              };                                                                                                    
4151              View finalView = pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET               
4152                      ? ((PendingAddWidgetInfo) pendingInfo).boundWidget : null;                                    
4153                                                                                                                    
4154              if (finalView instanceof AppWidgetHostView && updateWidgetSize) {                                     
4155                  AppWidgetHostView awhv = (AppWidgetHostView) finalView;                                           
4156                  AppWidgetResizeFrame.updateWidgetSizeRanges(awhv, mLauncher, item.spanX,                          
4157                          item.spanY);                                                                              
4158              }                                                                                                     
4159                                                                                                                    
4160              int animationStyle = ANIMATE_INTO_POSITION_AND_DISAPPEAR;                                             
4161              if (pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET &&                         
4162                      ((PendingAddWidgetInfo) pendingInfo).info.configure != null) {                                
4163                  animationStyle = ANIMATE_INTO_POSITION_AND_REMAIN;                                                
4164              }                                                                                                     
4165              animateWidgetDrop(info, cellLayout, d.dragView, onAnimationCompleteRunnable,                          
4166                      animationStyle, finalView, true);                                                             
4167          } else {                                                                                                  
4168              // This is for other drag/drop cases, like dragging from All Apps                                     
4169              View view = null;                                                                                     
4170                                                                                                                    
4171              switch (info.itemType) {                                                                              
4172              case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                                                
4173              case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                                   
4174                  if (info.container == NO_ID && info instanceof AppInfo) {                                         
4175                      // Came from all apps -- make a copy                                                          
4176                      info = new ShortcutInfo((AppInfo) info);                                                      
4177                  }                                                                                                 
4178                  view = mLauncher.createShortcut(R.layout.application, cellLayout,                                 
4179                          (ShortcutInfo) info);                                                                     
4180                  break;                                                                                            
4181              case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                                     
4182                  view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher, cellLayout,                            
4183                          (FolderInfo) info, mIconCache);                                                           
4184                  break;                                                                                            
4185              default:                                                                                              
4186                  throw new IllegalStateException("Unknown item type: " + info.itemType);                           
4187              }                                                                                                     
4188                                                                                                                    
4189              // First we find the cell nearest to point at which the item is                                       
4190              // dropped, without any consideration to whether there is an item there.                              
4191              if (touchXY != null) {                                                                                
4192                  mTargetCell = findNearestArea((int) touchXY[0], (int) touchXY[1], spanX, spanY,                   
4193                          cellLayout, mTargetCell);                                                                 
4194                  float distance = cellLayout.getDistanceFromCell(mDragViewVisualCenter[0],                         
4195                          mDragViewVisualCenter[1], mTargetCell);                                                   
4196                  d.postAnimationRunnable = exitSpringLoadedRunnable;                                               
4197                  if (createUserFolderIfNecessary(view, container, cellLayout, mTargetCell, distance,               
4198                          true, d.dragView, d.postAnimationRunnable)) {                                             
4199                      return;                                                                                       
4200                  }                                                                                                 
4201                  if (addToExistingFolderIfNecessary(view, cellLayout, mTargetCell, distance, d,                    
4202                          true)) {                                                                                  
4203                      return;                                                                                       
4204                  }                                                                                                 
4205              }                                                                                                     
4206                                                                                                                    
4207              if (touchXY != null) {                                                                                
4208                  // when dragging and dropping, just find the closest free spot                                    
4209                  mTargetCell = cellLayout.performReorder((int) mDragViewVisualCenter[0],                           
4210                          (int) mDragViewVisualCenter[1], 1, 1, 1, 1,                                               
4211                          null, mTargetCell, null, CellLayout.MODE_ON_DROP_EXTERNAL);                               
4212              } else {                                                                                              
4213                  cellLayout.findCellForSpan(mTargetCell, 1, 1);                                                    
4214              }                                                                                                     
4215 +            // Add the item to DB before adding to screen ensures that the container and other                    
4216 +            // values of the info is properly updated.                                                            
4217 +            LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screenId,                           
4218 +                    mTargetCell[0], mTargetCell[1]);                                                              
4219 +                                                                                                                  
4220              addInScreen(view, container, screenId, mTargetCell[0], mTargetCell[1], info.spanX,                    
4221                      info.spanY, insertAtFirst);                                                                   
4222              cellLayout.onDropChild(view);                                                                         
4223 -            CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();                        
4224              cellLayout.getShortcutsAndWidgets().measureChild(view);                                               
4225 -                                                                                                                  
4226 -            LauncherModel.addOrMoveItemInDatabase(mLauncher, info, container, screenId,                           
4227 -                    lp.cellX, lp.cellY);                                                                          
4228                                                                                                                    
4229              if (d.dragView != null) {                                                                             
4230                  // We wrap the animation call in the temporary set and reset of the current                       
4231                  // cellLayout to its final transform -- this means we animate the drag view to                    
4232                  // the correct final location.                                                                    
4233                  setFinalTransitionTransform(cellLayout);                                                          
4234                  mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, view,                                
4235                          exitSpringLoadedRunnable, this);                                                          
4236                  resetTransitionTransform(cellLayout);                                                             
4237              }                                                                                                     
4238          }                                                                                                         
4239      }                                                                                                             
4240                                                                                                                    
4241      public Bitmap createWidgetBitmap(ItemInfo widgetInfo, View layout) {                                          
4242          int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(widgetInfo.spanX,                          
4243                  widgetInfo.spanY, widgetInfo, false);                                                             
4244          int visibility = layout.getVisibility();                                                                  
4245          layout.setVisibility(VISIBLE);                                                                            
4246                                                                                                                    
4247          int width = MeasureSpec.makeMeasureSpec(unScaledSize[0], MeasureSpec.EXACTLY);                            
4248          int height = MeasureSpec.makeMeasureSpec(unScaledSize[1], MeasureSpec.EXACTLY);                           
4249          Bitmap b = Bitmap.createBitmap(unScaledSize[0], unScaledSize[1],                                          
4250                  Bitmap.Config.ARGB_8888);                                                                         
4251 -        Canvas c = new Canvas(b);                                                                                 
4252 +        mCanvas.setBitmap(b);                                                                                     
4253                                                                                                                    
4254          layout.measure(width, height);                                                                            
4255          layout.layout(0, 0, unScaledSize[0], unScaledSize[1]);                                                    
4256 -        layout.draw(c);                                                                                           
4257 -        c.setBitmap(null);                                                                                        
4258 +        layout.draw(mCanvas);                                                                                     
4259 +        mCanvas.setBitmap(null);                                                                                  
4260          layout.setVisibility(visibility);                                                                         
4261          return b;                                                                                                 
4262      }                                                                                                             
4263                                                                                                                    
4264      private void getFinalPositionForDropAnimation(int[] loc, float[] scaleXY,                                     
4265              DragView dragView, CellLayout layout, ItemInfo info, int[] targetCell,                                
4266              boolean external, boolean scale) {                                                                    
4267          // Now we animate the dragView, (ie. the widget or shortcut preview) into its final                       
4268          // location and size on the home screen.                                                                  
4269          int spanX = info.spanX;                                                                                   
4270          int spanY = info.spanY;                                                                                   
4271                                                                                                                    
4272          Rect r = estimateItemPosition(layout, info, targetCell[0], targetCell[1], spanX, spanY);                  
4273          loc[0] = r.left;                                                                                          
4274          loc[1] = r.top;                                                                                           
4275                                                                                                                    
4276          setFinalTransitionTransform(layout);                                                                      
4277          float cellLayoutScale =                                                                                   
4278                  mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(layout, loc, true);                     
4279          resetTransitionTransform(layout);                                                                         
4280                                                                                                                    
4281          float dragViewScaleX;                                                                                     
4282          float dragViewScaleY;                                                                                     
4283          if (scale) {                                                                                              
4284              dragViewScaleX = (1.0f * r.width()) / dragView.getMeasuredWidth();                                    
4285              dragViewScaleY = (1.0f * r.height()) / dragView.getMeasuredHeight();                                  
4286          } else {                                                                                                  
4287              dragViewScaleX = 1f;                                                                                  
4288              dragViewScaleY = 1f;                                                                                  
4289          }                                                                                                         
4290                                                                                                                    
4291          // The animation will scale the dragView about its center, so we need to center about                     
4292          // the final location.                                                                                    
4293          loc[0] -= (dragView.getMeasuredWidth() - cellLayoutScale * r.width()) / 2;                                
4294          loc[1] -= (dragView.getMeasuredHeight() - cellLayoutScale * r.height()) / 2;                              
4295                                                                                                                    
4296          scaleXY[0] = dragViewScaleX * cellLayoutScale;                                                            
4297          scaleXY[1] = dragViewScaleY * cellLayoutScale;                                                            
4298      }                                                                                                             
4299                                                                                                                    
4300      public void animateWidgetDrop(ItemInfo info, CellLayout cellLayout, DragView dragView,                        
4301              final Runnable onCompleteRunnable, int animationType, final View finalView,                           
4302              boolean external) {                                                                                   
4303          Rect from = new Rect();                                                                                   
4304          mLauncher.getDragLayer().getViewRectRelativeToSelf(dragView, from);                                       
4305                                                                                                                    
4306          int[] finalPos = new int[2];                                                                              
4307          float scaleXY[] = new float[2];                                                                           
4308          boolean scalePreview = !(info instanceof PendingAddShortcutInfo);                                         
4309          getFinalPositionForDropAnimation(finalPos, scaleXY, dragView, cellLayout, info, mTargetCell,              
4310                  external, scalePreview);                                                                          
4311                                                                                                                    
4312          Resources res = mLauncher.getResources();                                                                 
4313          final int duration = res.getInteger(R.integer.config_dropAnimMaxDuration) - 200;                          
4314                                                                                                                    
4315          // In the case where we've prebound the widget, we remove it from the DragLayer                           
4316          if (finalView instanceof AppWidgetHostView && external) {                                                 
4317              Log.d(TAG, "6557954 Animate widget drop, final view is appWidgetHostView");                           
4318              mLauncher.getDragLayer().removeView(finalView);                                                       
4319          }                                                                                                         
4320          if ((animationType == ANIMATE_INTO_POSITION_AND_RESIZE || external) && finalView != null) {               
4321              Bitmap crossFadeBitmap = createWidgetBitmap(info, finalView);                                         
4322              dragView.setCrossFadeBitmap(crossFadeBitmap);                                                         
4323              dragView.crossFade((int) (duration * 0.8f));                                                          
4324          } else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET && external) {                 
4325              scaleXY[0] = scaleXY[1] = Math.min(scaleXY[0],  scaleXY[1]);                                          
4326          }                                                                                                         
4327                                                                                                                    
4328          DragLayer dragLayer = mLauncher.getDragLayer();                                                           
4329          if (animationType == CANCEL_TWO_STAGE_WIDGET_DROP_ANIMATION) {                                            
4330              mLauncher.getDragLayer().animateViewIntoPosition(dragView, finalPos, 0f, 0.1f, 0.1f,                  
4331                      DragLayer.ANIMATION_END_DISAPPEAR, onCompleteRunnable, duration);                             
4332          } else {                                                                                                  
4333              int endStyle;                                                                                         
4334              if (animationType == ANIMATE_INTO_POSITION_AND_REMAIN) {                                              
4335                  endStyle = DragLayer.ANIMATION_END_REMAIN_VISIBLE;                                                
4336              } else {                                                                                              
4337                  endStyle = DragLayer.ANIMATION_END_DISAPPEAR;;                                                    
4338              }                                                                                                     
4339                                                                                                                    
4340              Runnable onComplete = new Runnable() {                                                                
4341                  @Override                                                                                         
4342                  public void run() {                                                                               
4343                      if (finalView != null) {                                                                      
4344                          finalView.setVisibility(VISIBLE);                                                         
4345                      }                                                                                             
4346                      if (onCompleteRunnable != null) {                                                             
4347                          onCompleteRunnable.run();                                                                 
4348                      }                                                                                             
4349                  }                                                                                                 
4350              };                                                                                                    
4351              dragLayer.animateViewIntoPosition(dragView, from.left, from.top, finalPos[0],                         
4352                      finalPos[1], 1, 1, 1, scaleXY[0], scaleXY[1], onComplete, endStyle,                           
4353                      duration, this);                                                                              
4354          }                                                                                                         
4355      }                                                                                                             
4356                                                                                                                    
4357      public void setFinalTransitionTransform(CellLayout layout) {                                                  
4358          if (isSwitchingState()) {                                                                                 
4359              mCurrentScale = getScaleX();                                                                          
4360              setScaleX(mNewScale);                                                                                 
4361              setScaleY(mNewScale);                                                                                 
4362          }                                                                                                         
4363      }                                                                                                             
4364      public void resetTransitionTransform(CellLayout layout) {                                                     
4365          if (isSwitchingState()) {                                                                                 
4366              setScaleX(mCurrentScale);                                                                             
4367              setScaleY(mCurrentScale);                                                                             
4368          }                                                                                                         
4369      }                                                                                                             
4370                                                                                                                    
4371      /**                                                                                                           
4372       * Return the current {@link CellLayout}, correctly picking the destination                                   
4373       * screen while a scroll is in progress.                                                                      
4374       */                                                                                                           
4375      public CellLayout getCurrentDropLayout() {                                                                    
4376          return (CellLayout) getChildAt(getNextPage());                                                            
4377      }                                                                                                             
4378                                                                                                                    
4379      /**                                                                                                           
4380       * Return the current CellInfo describing our current drag; this method exists                                
4381       * so that Launcher can sync this object with the correct info when the activity is created/                  
4382       * destroyed                                                                                                  
4383       *                                                                                                            
4384       */                                                                                                           
4385      public CellLayout.CellInfo getDragInfo() {                                                                    
4386          return mDragInfo;                                                                                         
4387      }                                                                                                             
4388                                                                                                                    
4389      public int getCurrentPageOffsetFromCustomContent() {                                                          
4390          return getNextPage() - numCustomPages();                                                                  
4391      }                                                                                                             
4392                                                                                                                    
4393      /**                                                                                                           
4394       * Calculate the nearest cell where the given object would be dropped.                                        
4395       *                                                                                                            
4396       * pixelX and pixelY should be in the coordinate system of layout                                             
4397       */                                                                                                           
4398      private int[] findNearestArea(int pixelX, int pixelY,                                                         
4399              int spanX, int spanY, CellLayout layout, int[] recycle) {                                             
4400          return layout.findNearestArea(                                                                            
4401                  pixelX, pixelY, spanX, spanY, recycle);                                                           
4402      }                                                                                                             
4403                                                                                                                    
4404      void setup(DragController dragController) {                                                                   
4405          mSpringLoadedDragController = new SpringLoadedDragController(mLauncher);                                  
4406          mDragController = dragController;                                                                         
4407                                                                                                                    
4408          // hardware layers on children are enabled on startup, but should be disabled until                       
4409          // needed                                                                                                 
4410          updateChildrenLayersEnabled(false);                                                                       
4411      }                                                                                                             
4412                                                                                                                    
4413      /**                                                                                                           
4414       * Called at the end of a drag which originated on the workspace.                                             
4415       */                                                                                                           
4416      public void onDropCompleted(final View target, final DragObject d,                                            
4417              final boolean isFlingToDelete, final boolean success) {                                               
4418          if (mDeferDropAfterUninstall) {                                                                           
4419              mDeferredAction = new Runnable() {                                                                    
4420                  public void run() {                                                                               
4421                      onDropCompleted(target, d, isFlingToDelete, success);                                         
4422                      mDeferredAction = null;                                                                       
4423                  }                                                                                                 
4424              };                                                                                                    
4425              return;                                                                                               
4426          }                                                                                                         
4427                                                                                                                    
4428          boolean beingCalledAfterUninstall = mDeferredAction != null;                                              
4429                                                                                                                    
4430          if (success && !(beingCalledAfterUninstall && !mUninstallSuccessful)) {                                   
4431              if (target != this && mDragInfo != null) {                                                            
4432                  CellLayout parentCell = getParentCellLayoutForView(mDragInfo.cell);                               
4433                  if (parentCell != null) {                                                                         
4434                      parentCell.removeView(mDragInfo.cell);                                                        
4435 +                } else if (LauncherAppState.isDogfoodBuild()) {                                                   
4436 +                    throw new NullPointerException("mDragInfo.cell has null parent");                             
4437                  }                                                                                                 
4438                  if (mDragInfo.cell instanceof DropTarget) {                                                       
4439                      mDragController.removeDropTarget((DropTarget) mDragInfo.cell);                                
4440                  }                                                                                                 
4441 -                // If we move the item to anything not on the Workspace, check if any empty                       
4442 -                // screens need to be removed. If we dropped back on the workspace, this will                     
4443 -                // be done post drop animation.                                                                   
4444 -                removeExtraEmptyScreen(true, null, 0, true);                                                      
4445              }                                                                                                     
4446          } else if (mDragInfo != null) {                                                                           
4447              CellLayout cellLayout;                                                                                
4448              if (mLauncher.isHotseatLayout(target)) {                                                              
4449                  cellLayout = mLauncher.getHotseat().getLayout();                                                  
4450              } else {                                                                                              
4451                  cellLayout = getScreenWithId(mDragInfo.screenId);                                                 
4452              }                                                                                                     
4453              if (cellLayout == null && LauncherAppState.isDogfoodBuild()) {                                        
4454                  throw new RuntimeException("Invalid state: cellLayout == null in "                                
4455                          + "Workspace#onDropCompleted. Please file a bug. ");                                      
4456              }                                                                                                     
4457              if (cellLayout != null) {                                                                             
4458                  cellLayout.onDropChild(mDragInfo.cell);                                                           
4459              }                                                                                                     
4460          }                                                                                                         
4461          if ((d.cancelled || (beingCalledAfterUninstall && !mUninstallSuccessful))                                 
4462                  && mDragInfo.cell != null) {                                                                      
4463              mDragInfo.cell.setVisibility(VISIBLE);                                                                
4464          }                                                                                                         
4465          mDragOutline = null;                                                                                      
4466          mDragInfo = null;                                                                                         
4467      }                                                                                                             
4468                                                                                                                    
4469      public void deferCompleteDropAfterUninstallActivity() {                                                       
4470          mDeferDropAfterUninstall = true;                                                                          
4471      }                                                                                                             
4472                                                                                                                    
4473      /// maybe move this into a smaller part                                                                       
4474      public void onUninstallActivityReturned(boolean success) {                                                    
4475          mDeferDropAfterUninstall = false;                                                                         
4476          mUninstallSuccessful = success;                                                                           
4477          if (mDeferredAction != null) {                                                                            
4478              mDeferredAction.run();                                                                                
4479          }                                                                                                         
4480      }                                                                                                             
4481                                                                                                                    
4482      void updateItemLocationsInDatabase(CellLayout cl) {                                                           
4483          int count = cl.getShortcutsAndWidgets().getChildCount();                                                  
4484                                                                                                                    
4485          long screenId = getIdForScreen(cl);                                                                       
4486          int container = Favorites.CONTAINER_DESKTOP;                                                              
4487                                                                                                                    
4488          if (mLauncher.isHotseatLayout(cl)) {                                                                      
4489              screenId = -1;                                                                                        
4490              container = Favorites.CONTAINER_HOTSEAT;                                                              
4491          }                                                                                                         
4492                                                                                                                    
4493          for (int i = 0; i < count; i++) {                                                                         
4494              View v = cl.getShortcutsAndWidgets().getChildAt(i);                                                   
4495              ItemInfo info = (ItemInfo) v.getTag();                                                                
4496              // Null check required as the AllApps button doesn't have an item info                                
4497              if (info != null && info.requiresDbUpdate) {                                                          
4498                  info.requiresDbUpdate = false;                                                                    
4499                  LauncherModel.modifyItemInDatabase(mLauncher, info, container, screenId, info.cellX,              
4500                          info.cellY, info.spanX, info.spanY);                                                      
4501              }                                                                                                     
4502          }                                                                                                         
4503      }                                                                                                             
4504                                                                                                                    
4505      ArrayList<ComponentName> getUniqueComponents(boolean stripDuplicates, ArrayList<ComponentName> duplicates) {  
4506          ArrayList<ComponentName> uniqueIntents = new ArrayList<ComponentName>();                                  
4507          getUniqueIntents((CellLayout) mLauncher.getHotseat().getLayout(), uniqueIntents, duplicates, false);      
4508          int count = getChildCount();                                                                              
4509          for (int i = 0; i < count; i++) {                                                                         
4510              CellLayout cl = (CellLayout) getChildAt(i);                                                           
4511              getUniqueIntents(cl, uniqueIntents, duplicates, false);                                               
4512          }                                                                                                         
4513          return uniqueIntents;                                                                                     
4514      }                                                                                                             
4515                                                                                                                    
4516      void getUniqueIntents(CellLayout cl, ArrayList<ComponentName> uniqueIntents,                                  
4517              ArrayList<ComponentName> duplicates, boolean stripDuplicates) {                                       
4518          int count = cl.getShortcutsAndWidgets().getChildCount();                                                  
4519                                                                                                                    
4520          ArrayList<View> children = new ArrayList<View>();                                                         
4521          for (int i = 0; i < count; i++) {                                                                         
4522              View v = cl.getShortcutsAndWidgets().getChildAt(i);                                                   
4523              children.add(v);                                                                                      
4524          }                                                                                                         
4525                                                                                                                    
4526          for (int i = 0; i < count; i++) {                                                                         
4527              View v = children.get(i);                                                                             
4528              ItemInfo info = (ItemInfo) v.getTag();                                                                
4529              // Null check required as the AllApps button doesn't have an item info                                
4530              if (info instanceof ShortcutInfo) {                                                                   
4531                  ShortcutInfo si = (ShortcutInfo) info;                                                            
4532                  ComponentName cn = si.intent.getComponent();                                                      
4533                                                                                                                    
4534                  Uri dataUri = si.intent.getData();                                                                
4535                  // If dataUri is not null / empty or if this component isn't one that would                       
4536                  // have previously showed up in the AllApps list, then this is a widget-type                      
4537                  // shortcut, so ignore it.                                                                        
4538                  if (dataUri != null && !dataUri.equals(Uri.EMPTY)) {                                              
4539                      continue;                                                                                     
4540                  }                                                                                                 
4541                                                                                                                    
4542                  if (!uniqueIntents.contains(cn)) {                                                                
4543                      uniqueIntents.add(cn);                                                                        
4544                  } else {                                                                                          
4545                      if (stripDuplicates) {                                                                        
4546                          cl.removeViewInLayout(v);                                                                 
4547                          LauncherModel.deleteItemFromDatabase(mLauncher, si);                                      
4548                      }                                                                                             
4549                      if (duplicates != null) {                                                                     
4550                          duplicates.add(cn);                                                                       
4551                      }                                                                                             
4552                  }                                                                                                 
4553              }                                                                                                     
4554              if (v instanceof FolderIcon) {                                                                        
4555                  FolderIcon fi = (FolderIcon) v;                                                                   
4556                  ArrayList<View> items = fi.getFolder().getItemsInReadingOrder();                                  
4557                  for (int j = 0; j < items.size(); j++) {                                                          
4558                      if (items.get(j).getTag() instanceof ShortcutInfo) {                                          
4559                          ShortcutInfo si = (ShortcutInfo) items.get(j).getTag();                                   
4560                          ComponentName cn = si.intent.getComponent();                                              
4561                                                                                                                    
4562                          Uri dataUri = si.intent.getData();                                                        
4563                          // If dataUri is not null / empty or if this component isn't one that would               
4564                          // have previously showed up in the AllApps list, then this is a widget-type              
4565                          // shortcut, so ignore it.                                                                
4566                          if (dataUri != null && !dataUri.equals(Uri.EMPTY)) {                                      
4567                              continue;                                                                             
4568                          }                                                                                         
4569                                                                                                                    
4570                          if (!uniqueIntents.contains(cn)) {                                                        
4571                              uniqueIntents.add(cn);                                                                
4572                          }  else {                                                                                 
4573                              if (stripDuplicates) {                                                                
4574                                  fi.getFolderInfo().remove(si);                                                    
4575                                  LauncherModel.deleteItemFromDatabase(mLauncher, si);                              
4576                              }                                                                                     
4577                              if (duplicates != null) {                                                             
4578                                  duplicates.add(cn);                                                               
4579                              }                                                                                     
4580                          }                                                                                         
4581                      }                                                                                             
4582                  }                                                                                                 
4583              }                                                                                                     
4584          }                                                                                                         
4585      }                                                                                                             
4586                                                                                                                    
4587      void saveWorkspaceToDb() {                                                                                    
4588          saveWorkspaceScreenToDb((CellLayout) mLauncher.getHotseat().getLayout());                                 
4589          int count = getChildCount();                                                                              
4590          for (int i = 0; i < count; i++) {                                                                         
4591              CellLayout cl = (CellLayout) getChildAt(i);                                                           
4592              saveWorkspaceScreenToDb(cl);                                                                          
4593          }                                                                                                         
4594      }                                                                                                             
4595                                                                                                                    
4596      void saveWorkspaceScreenToDb(CellLayout cl) {                                                                 
4597          int count = cl.getShortcutsAndWidgets().getChildCount();                                                  
4598                                                                                                                    
4599          long screenId = getIdForScreen(cl);                                                                       
4600          int container = Favorites.CONTAINER_DESKTOP;                                                              
4601                                                                                                                    
4602          Hotseat hotseat = mLauncher.getHotseat();                                                                 
4603          if (mLauncher.isHotseatLayout(cl)) {                                                                      
4604              screenId = -1;                                                                                        
4605              container = Favorites.CONTAINER_HOTSEAT;                                                              
4606          }                                                                                                         
4607                                                                                                                    
4608          for (int i = 0; i < count; i++) {                                                                         
4609              View v = cl.getShortcutsAndWidgets().getChildAt(i);                                                   
4610              ItemInfo info = (ItemInfo) v.getTag();                                                                
4611              // Null check required as the AllApps button doesn't have an item info                                
4612              if (info != null) {                                                                                   
4613                  int cellX = info.cellX;                                                                           
4614                  int cellY = info.cellY;                                                                           
4615                  if (container == Favorites.CONTAINER_HOTSEAT) {                                                   
4616                      cellX = hotseat.getCellXFromOrder((int) info.screenId);                                       
4617                      cellY = hotseat.getCellYFromOrder((int) info.screenId);                                       
4618                  }                                                                                                 
4619                  LauncherModel.addItemToDatabase(mLauncher, info, container, screenId, cellX,                      
4620                          cellY, false);                                                                            
4621              }                                                                                                     
4622              if (v instanceof FolderIcon) {                                                                        
4623                  FolderIcon fi = (FolderIcon) v;                                                                   
4624                  fi.getFolder().addItemLocationsInDatabase();                                                      
4625              }                                                                                                     
4626          }                                                                                                         
4627      }                                                                                                             
4628                                                                                                                    
4629      @Override                                                                                                     
4630      public float getIntrinsicIconScaleFactor() {                                                                  
4631          return 1f;                                                                                                
4632      }                                                                                                             
4633                                                                                                                    
4634      @Override                                                                                                     
4635      public boolean supportsFlingToDelete() {                                                                      
4636          return true;                                                                                              
4637      }                                                                                                             
4638                                                                                                                    
4639      @Override                                                                                                     
4640      public boolean supportsAppInfoDropTarget() {                                                                  
4641          return false;                                                                                             
4642      }                                                                                                             
4643                                                                                                                    
4644      @Override                                                                                                     
4645      public boolean supportsDeleteDropTarget() {                                                                   
4646          return true;                                                                                              
4647      }                                                                                                             
4648                                                                                                                    
4649      @Override                                                                                                     
4650      public void onFlingToDelete(DragObject d, int x, int y, PointF vec) {                                         
4651          // Do nothing                                                                                             
4652      }                                                                                                             
4653                                                                                                                    
4654      @Override                                                                                                     
4655      public void onFlingToDeleteCompleted() {                                                                      
4656          // Do nothing                                                                                             
4657      }                                                                                                             
4658                                                                                                                    
4659      public boolean isDropEnabled() {                                                                              
4660          return true;                                                                                              
4661      }                                                                                                             
4662                                                                                                                    
4663      @Override                                                                                                     
4664      protected void onRestoreInstanceState(Parcelable state) {                                                     
4665          super.onRestoreInstanceState(state);                                                                      
4666          Launcher.setScreen(mCurrentPage);                                                                         
4667      }                                                                                                             
4668                                                                                                                    
4669      @Override                                                                                                     
4670      protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {                              
4671          // We don't dispatch restoreInstanceState to our children using this code path.                           
4672          // Some pages will be restored immediately as their items are bound immediately, and                      
4673          // others we will need to wait until after their items are bound.                                         
4674          mSavedStates = container;                                                                                 
4675      }                                                                                                             
4676                                                                                                                    
4677      public void restoreInstanceStateForChild(int child) {                                                         
4678          if (mSavedStates != null) {                                                                               
4679              mRestoredPages.add(child);                                                                            
4680              CellLayout cl = (CellLayout) getChildAt(child);                                                       
4681              if (cl != null) {                                                                                     
4682                  cl.restoreInstanceState(mSavedStates);                                                            
4683              }                                                                                                     
4684          }                                                                                                         
4685      }                                                                                                             
4686                                                                                                                    
4687      public void restoreInstanceStateForRemainingPages() {                                                         
4688          int count = getChildCount();                                                                              
4689          for (int i = 0; i < count; i++) {                                                                         
4690              if (!mRestoredPages.contains(i)) {                                                                    
4691                  restoreInstanceStateForChild(i);                                                                  
4692              }                                                                                                     
4693          }                                                                                                         
4694          mRestoredPages.clear();                                                                                   
4695          mSavedStates = null;                                                                                      
4696      }                                                                                                             
4697                                                                                                                    
4698      @Override                                                                                                     
4699      public void scrollLeft() {                                                                                    
4700 -        if (!isSmall() && !mIsSwitchingState) {                                                                   
4701 +        if (!workspaceInModalState() && !mIsSwitchingState) {                                                     
4702              super.scrollLeft();                                                                                   
4703          }                                                                                                         
4704          Folder openFolder = getOpenFolder();                                                                      
4705          if (openFolder != null) {                                                                                 
4706              openFolder.completeDragExit();                                                                        
4707          }                                                                                                         
4708      }                                                                                                             
4709                                                                                                                    
4710      @Override                                                                                                     
4711      public void scrollRight() {                                                                                   
4712 -        if (!isSmall() && !mIsSwitchingState) {                                                                   
4713 +        if (!workspaceInModalState() && !mIsSwitchingState) {                                                     
4714              super.scrollRight();                                                                                  
4715          }                                                                                                         
4716          Folder openFolder = getOpenFolder();                                                                      
4717          if (openFolder != null) {                                                                                 
4718              openFolder.completeDragExit();                                                                        
4719          }                                                                                                         
4720      }                                                                                                             
4721                                                                                                                    
4722      @Override                                                                                                     
4723      public boolean onEnterScrollArea(int x, int y, int direction) {                                               
4724          // Ignore the scroll area if we are dragging over the hot seat                                            
4725          boolean isPortrait = !LauncherAppState.isScreenLandscape(getContext());                                   
4726          if (mLauncher.getHotseat() != null && isPortrait) {                                                       
4727              Rect r = new Rect();                                                                                  
4728              mLauncher.getHotseat().getHitRect(r);                                                                 
4729              if (r.contains(x, y)) {                                                                               
4730                  return false;                                                                                     
4731              }                                                                                                     
4732          }                                                                                                         
4733                                                                                                                    
4734          boolean result = false;                                                                                   
4735 -        if (!isSmall() && !mIsSwitchingState && getOpenFolder() == null) {                                        
4736 +        if (!workspaceInModalState() && !mIsSwitchingState && getOpenFolder() == null) {                          
4737              mInScrollArea = true;                                                                                 
4738                                                                                                                    
4739              final int page = getNextPage() +                                                                      
4740                         (direction == DragController.SCROLL_LEFT ? -1 : 1);                                        
4741              // We always want to exit the current layout to ensure parity of enter / exit                         
4742              setCurrentDropLayout(null);                                                                           
4743                                                                                                                    
4744              if (0 <= page && page < getChildCount()) {                                                            
4745                  // Ensure that we are not dragging over to the custom content screen                              
4746                  if (getScreenIdForPageIndex(page) == CUSTOM_CONTENT_SCREEN_ID) {                                  
4747                      return false;                                                                                 
4748                  }                                                                                                 
4749                                                                                                                    
4750                  CellLayout layout = (CellLayout) getChildAt(page);                                                
4751                  setCurrentDragOverlappingLayout(layout);                                                          
4752                                                                                                                    
4753                  // Workspace is responsible for drawing the edge glow on adjacent pages,                          
4754                  // so we need to redraw the workspace when this may have changed.                                 
4755                  invalidate();                                                                                     
4756                  result = true;                                                                                    
4757              }                                                                                                     
4758          }                                                                                                         
4759          return result;                                                                                            
4760      }                                                                                                             
4761                                                                                                                    
4762      @Override                                                                                                     
4763      public boolean onExitScrollArea() {                                                                           
4764          boolean result = false;                                                                                   
4765          if (mInScrollArea) {                                                                                      
4766              invalidate();                                                                                         
4767              CellLayout layout = getCurrentDropLayout();                                                           
4768              setCurrentDropLayout(layout);                                                                         
4769              setCurrentDragOverlappingLayout(layout);                                                              
4770                                                                                                                    
4771              result = true;                                                                                        
4772              mInScrollArea = false;                                                                                
4773          }                                                                                                         
4774          return result;                                                                                            
4775      }                                                                                                             
4776                                                                                                                    
4777      private void onResetScrollArea() {                                                                            
4778          setCurrentDragOverlappingLayout(null);                                                                    
4779          mInScrollArea = false;                                                                                    
4780      }                                                                                                             
4781                                                                                                                    
4782      /**                                                                                                           
4783       * Returns a specific CellLayout                                                                              
4784       */                                                                                                           
4785      CellLayout getParentCellLayoutForView(View v) {                                                               
4786          ArrayList<CellLayout> layouts = getWorkspaceAndHotseatCellLayouts();                                      
4787          for (CellLayout layout : layouts) {                                                                       
4788              if (layout.getShortcutsAndWidgets().indexOfChild(v) > -1) {                                           
4789                  return layout;                                                                                    
4790              }                                                                                                     
4791          }                                                                                                         
4792          return null;                                                                                              
4793      }                                                                                                             
4794                                                                                                                    
4795      /**                                                                                                           
4796       * Returns a list of all the CellLayouts in the workspace.                                                    
4797       */                                                                                                           
4798      ArrayList<CellLayout> getWorkspaceAndHotseatCellLayouts() {                                                   
4799          ArrayList<CellLayout> layouts = new ArrayList<CellLayout>();                                              
4800          int screenCount = getChildCount();                                                                        
4801          for (int screen = 0; screen < screenCount; screen++) {                                                    
4802              layouts.add(((CellLayout) getChildAt(screen)));                                                       
4803          }                                                                                                         
4804          if (mLauncher.getHotseat() != null) {                                                                     
4805              layouts.add(mLauncher.getHotseat().getLayout());                                                      
4806          }                                                                                                         
4807          return layouts;                                                                                           
4808      }                                                                                                             
4809                                                                                                                    
4810      /**                                                                                                           
4811       * We should only use this to search for specific children.  Do not use this method to modify                 
4812       * ShortcutsAndWidgetsContainer directly. Includes ShortcutAndWidgetContainers from                           
4813       * the hotseat and workspace pages                                                                            
4814       */                                                                                                           
4815      ArrayList<ShortcutAndWidgetContainer> getAllShortcutAndWidgetContainers() {                                   
4816          ArrayList<ShortcutAndWidgetContainer> childrenLayouts =                                                   
4817                  new ArrayList<ShortcutAndWidgetContainer>();                                                      
4818          int screenCount = getChildCount();                                                                        
4819          for (int screen = 0; screen < screenCount; screen++) {                                                    
4820              childrenLayouts.add(((CellLayout) getChildAt(screen)).getShortcutsAndWidgets());                      
4821          }                                                                                                         
4822          if (mLauncher.getHotseat() != null) {                                                                     
4823              childrenLayouts.add(mLauncher.getHotseat().getLayout().getShortcutsAndWidgets());                     
4824          }                                                                                                         
4825          return childrenLayouts;                                                                                   
4826      }                                                                                                             
4827                                                                                                                    
4828 -    public Folder getFolderForTag(Object tag) {                                                                   
4829 -        ArrayList<ShortcutAndWidgetContainer> childrenLayouts =                                                   
4830 -                getAllShortcutAndWidgetContainers();                                                              
4831 -        for (ShortcutAndWidgetContainer layout: childrenLayouts) {                                                
4832 -            int count = layout.getChildCount();                                                                   
4833 -            for (int i = 0; i < count; i++) {                                                                     
4834 -                View child = layout.getChildAt(i);                                                                
4835 -                if (child instanceof Folder) {                                                                    
4836 -                    Folder f = (Folder) child;                                                                    
4837 -                    if (f.getInfo() == tag && f.getInfo().opened) {                                               
4838 -                        return f;                                                                                 
4839 -                    }                                                                                             
4840 -                }                                                                                                 
4841 -            }                                                                                                     
4842 -        }                                                                                                         
4843 -        return null;                                                                                              
4844 -    }                                                                                                             
4845 -                                                                                                                  
4846 -    public View getViewForTag(Object tag) {                                                                       
4847 -        ArrayList<ShortcutAndWidgetContainer> childrenLayouts =                                                   
4848 -                getAllShortcutAndWidgetContainers();                                                              
4849 -        for (ShortcutAndWidgetContainer layout: childrenLayouts) {                                                
4850 -            int count = layout.getChildCount();                                                                   
4851 -            for (int i = 0; i < count; i++) {                                                                     
4852 -                View child = layout.getChildAt(i);                                                                
4853 -                if (child.getTag() == tag) {                                                                      
4854 -                    return child;                                                                                 
4855 -                }                                                                                                 
4856 -            }                                                                                                     
4857 -        }                                                                                                         
4858 -        return null;                                                                                              
4859 +    public Folder getFolderForTag(final Object tag) {                                                             
4860 +        return (Folder) getFirstMatch(new ItemOperator() {                                                        
4861 +                                                                                                                  
4862 +            @Override                                                                                             
4863 +            public boolean evaluate(ItemInfo info, View v, View parent) {                                         
4864 +                return (v instanceof Folder) && (((Folder) v).getInfo() == tag)                                   
4865 +                        && ((Folder) v).getInfo().opened;                                                         
4866 +            }                                                                                                     
4867 +        });                                                                                                       
4868 +    }                                                                                                             
4869 +                                                                                                                  
4870 +    public View getViewForTag(final Object tag) {                                                                 
4871 +        return getFirstMatch(new ItemOperator() {                                                                 
4872 +                                                                                                                  
4873 +            @Override                                                                                             
4874 +            public boolean evaluate(ItemInfo info, View v, View parent) {                                         
4875 +                return info == tag;                                                                               
4876 +            }                                                                                                     
4877 +        });                                                                                                       
4878 +    }                                                                                                             
4879 +                                                                                                                  
4880 +    public LauncherAppWidgetHostView getWidgetForAppWidgetId(final int appWidgetId) {                             
4881 +        return (LauncherAppWidgetHostView) getFirstMatch(new ItemOperator() {                                     
4882 +                                                                                                                  
4883 +            @Override                                                                                             
4884 +            public boolean evaluate(ItemInfo info, View v, View parent) {                                         
4885 +                return (info instanceof LauncherAppWidgetInfo) &&                                                 
4886 +                        ((LauncherAppWidgetInfo) info).appWidgetId == appWidgetId;                                
4887 +            }                                                                                                     
4888 +        });                                                                                                       
4889 +    }                                                                                                             
4890 +                                                                                                                  
4891 +    private View getFirstMatch(final ItemOperator operator) {                                                     
4892 +        final View[] value = new View[1];                                                                         
4893 +        mapOverItems(MAP_NO_RECURSE, new ItemOperator() {                                                         
4894 +            @Override                                                                                             
4895 +            public boolean evaluate(ItemInfo info, View v, View parent) {                                         
4896 +                if (operator.evaluate(info, v, parent)) {                                                         
4897 +                    value[0] = v;                                                                                 
4898 +                    return true;                                                                                  
4899 +                }                                                                                                 
4900 +                return false;                                                                                     
4901 +            }                                                                                                     
4902 +        });                                                                                                       
4903 +        return value[0];                                                                                          
4904      }                                                                                                             
4905                                                                                                                    
4906      void clearDropTargets() {                                                                                     
4907 -        ArrayList<ShortcutAndWidgetContainer> childrenLayouts =                                                   
4908 -                getAllShortcutAndWidgetContainers();                                                              
4909 -        for (ShortcutAndWidgetContainer layout: childrenLayouts) {                                                
4910 -            int childCount = layout.getChildCount();                                                              
4911 -            for (int j = 0; j < childCount; j++) {                                                                
4912 -                View v = layout.getChildAt(j);                                                                    
4913 +        mapOverItems(MAP_NO_RECURSE, new ItemOperator() {                                                         
4914 +            @Override                                                                                             
4915 +            public boolean evaluate(ItemInfo info, View v, View parent) {                                         
4916                  if (v instanceof DropTarget) {                                                                    
4917                      mDragController.removeDropTarget((DropTarget) v);                                             
4918                  }                                                                                                 
4919 -            }                                                                                                     
4920 -        }                                                                                                         
4921 +                // not done, process all the shortcuts                                                            
4922 +                return false;                                                                                     
4923 +            }                                                                                                     
4924 +        });                                                                                                       
4925      }                                                                                                             
4926                                                                                                                    
4927      // Removes ALL items that match a given package name, this is usually called when a package                   
4928      // has been removed and we want to remove all components (widgets, shortcuts, apps) that                      
4929      // belong to that package.                                                                                    
4930 -    void removeItemsByPackageName(final ArrayList<String> packages) {                                             
4931 +    void removeItemsByPackageName(final ArrayList<String> packages, final UserHandleCompat user) {                
4932          final HashSet<String> packageNames = new HashSet<String>();                                               
4933          packageNames.addAll(packages);                                                                            
4934                                                                                                                    
4935          // Filter out all the ItemInfos that this is going to affect                                              
4936          final HashSet<ItemInfo> infos = new HashSet<ItemInfo>();                                                  
4937          final HashSet<ComponentName> cns = new HashSet<ComponentName>();                                          
4938          ArrayList<CellLayout> cellLayouts = getWorkspaceAndHotseatCellLayouts();                                  
4939          for (CellLayout layoutParent : cellLayouts) {                                                             
4940              ViewGroup layout = layoutParent.getShortcutsAndWidgets();                                             
4941              int childCount = layout.getChildCount();                                                              
4942              for (int i = 0; i < childCount; ++i) {                                                                
4943                  View view = layout.getChildAt(i);                                                                 
4944                  infos.add((ItemInfo) view.getTag());                                                              
4945              }                                                                                                     
4946          }                                                                                                         
4947          LauncherModel.ItemInfoFilter filter = new LauncherModel.ItemInfoFilter() {                                
4948              @Override                                                                                             
4949              public boolean filterItem(ItemInfo parent, ItemInfo info,                                             
4950                                        ComponentName cn) {                                                         
4951 -                if (packageNames.contains(cn.getPackageName())) {                                                 
4952 +                if (packageNames.contains(cn.getPackageName())                                                    
4953 +                        && info.user.equals(user)) {                                                              
4954                      cns.add(cn);                                                                                  
4955                      return true;                                                                                  
4956                  }                                                                                                 
4957                  return false;                                                                                     
4958              }                                                                                                     
4959          };                                                                                                        
4960          LauncherModel.filterItemInfos(infos, filter);                                                             
4961                                                                                                                    
4962          // Remove the affected components                                                                         
4963 -        removeItemsByComponentName(cns);                                                                          
4964 +        removeItemsByComponentName(cns, user);                                                                    
4965      }                                                                                                             
4966                                                                                                                    
4967      // Removes items that match the application info specified, when applications are removed                     
4968      // as a part of an update, this is called to ensure that other widgets and application                        
4969      // shortcuts are not removed.                                                                                 
4970 -    void removeItemsByApplicationInfo(final ArrayList<AppInfo> appInfos) {                                        
4971 +    void removeItemsByApplicationInfo(final ArrayList<AppInfo> appInfos, UserHandleCompat user) {                 
4972          // Just create a hash table of all the specific components that this will affect                          
4973          HashSet<ComponentName> cns = new HashSet<ComponentName>();                                                
4974          for (AppInfo info : appInfos) {                                                                           
4975              cns.add(info.componentName);                                                                          
4976          }                                                                                                         
4977                                                                                                                    
4978          // Remove all the things                                                                                  
4979 -        removeItemsByComponentName(cns);                                                                          
4980 -    }                                                                                                             
4981 -                                                                                                                  
4982 -    void removeItemsByComponentName(final HashSet<ComponentName> componentNames) {                                
4983 +        removeItemsByComponentName(cns, user);                                                                    
4984 +    }                                                                                                             
4985 +                                                                                                                  
4986 +    void removeItemsByComponentName(final HashSet<ComponentName> componentNames,                                  
4987 +            final UserHandleCompat user) {                                                                        
4988          ArrayList<CellLayout> cellLayouts = getWorkspaceAndHotseatCellLayouts();                                  
4989          for (final CellLayout layoutParent: cellLayouts) {                                                        
4990              final ViewGroup layout = layoutParent.getShortcutsAndWidgets();                                       
4991                                                                                                                    
4992              final HashMap<ItemInfo, View> children = new HashMap<ItemInfo, View>();                               
4993              for (int j = 0; j < layout.getChildCount(); j++) {                                                    
4994                  final View view = layout.getChildAt(j);                                                           
4995                  children.put((ItemInfo) view.getTag(), view);                                                     
4996              }                                                                                                     
4997                                                                                                                    
4998              final ArrayList<View> childrenToRemove = new ArrayList<View>();                                       
4999              final HashMap<FolderInfo, ArrayList<ShortcutInfo>> folderAppsToRemove =                               
5000                      new HashMap<FolderInfo, ArrayList<ShortcutInfo>>();                                           
5001              LauncherModel.ItemInfoFilter filter = new LauncherModel.ItemInfoFilter() {                            
5002                  @Override                                                                                         
5003                  public boolean filterItem(ItemInfo parent, ItemInfo info,                                         
5004                                            ComponentName cn) {                                                     
5005                      if (parent instanceof FolderInfo) {                                                           
5006 -                        if (componentNames.contains(cn)) {                                                        
5007 +                        if (componentNames.contains(cn) && info.user.equals(user)) {                              
5008                              FolderInfo folder = (FolderInfo) parent;                                              
5009                              ArrayList<ShortcutInfo> appsToRemove;                                                 
5010                              if (folderAppsToRemove.containsKey(folder)) {                                         
5011                                  appsToRemove = folderAppsToRemove.get(folder);                                    
5012                              } else {                                                                              
5013                                  appsToRemove = new ArrayList<ShortcutInfo>();                                     
5014                                  folderAppsToRemove.put(folder, appsToRemove);                                     
5015                              }                                                                                     
5016                              appsToRemove.add((ShortcutInfo) info);                                                
5017                              return true;                                                                          
5018                          }                                                                                         
5019                      } else {                                                                                      
5020 -                        if (componentNames.contains(cn)) {                                                        
5021 +                        if (componentNames.contains(cn) && info.user.equals(user)) {                              
5022                              childrenToRemove.add(children.get(info));                                             
5023                              return true;                                                                          
5024                          }                                                                                         
5025                      }                                                                                             
5026                      return false;                                                                                 
5027                  }                                                                                                 
5028              };                                                                                                    
5029              LauncherModel.filterItemInfos(children.keySet(), filter);                                             
5030                                                                                                                    
5031              // Remove all the apps from their folders                                                             
5032              for (FolderInfo folder : folderAppsToRemove.keySet()) {                                               
5033                  ArrayList<ShortcutInfo> appsToRemove = folderAppsToRemove.get(folder);                            
5034                  for (ShortcutInfo info : appsToRemove) {                                                          
5035                      folder.remove(info);                                                                          
5036                  }                                                                                                 
5037              }                                                                                                     
5038                                                                                                                    
5039              // Remove all the other children                                                                      
5040              for (View child : childrenToRemove) {                                                                 
5041                  // Note: We can not remove the view directly from CellLayoutChildren as this                      
5042                  // does not re-mark the spaces as unoccupied.                                                     
5043                  layoutParent.removeViewInLayout(child);                                                           
5044                  if (child instanceof DropTarget) {                                                                
5045                      mDragController.removeDropTarget((DropTarget) child);                                         
5046                  }                                                                                                 
5047              }                                                                                                     
5048                                                                                                                    
5049              if (childrenToRemove.size() > 0) {                                                                    
5050                  layout.requestLayout();                                                                           
5051                  layout.invalidate();                                                                              
5052              }                                                                                                     
5053          }                                                                                                         
5054                                                                                                                    
5055          // Strip all the empty screens                                                                            
5056          stripEmptyScreens();                                                                                      
5057      }                                                                                                             
5058                                                                                                                    
5059 -    private void updateShortcut(HashMap<ComponentName, AppInfo> appsMap, ItemInfo info,                           
5060 -                                View child) {                                                                     
5061 -        ComponentName cn = info.getIntent().getComponent();                                                       
5062 -        if (cn != null) {                                                                                         
5063 -            AppInfo appInfo = appsMap.get(info.getIntent().getComponent());                                       
5064 -            if ((appInfo != null) && LauncherModel.isShortcutInfoUpdateable(info)) {                              
5065 -                ShortcutInfo shortcutInfo = (ShortcutInfo) info;                                                  
5066 -                BubbleTextView shortcut = (BubbleTextView) child;                                                 
5067 -                shortcutInfo.updateIcon(mIconCache);                                                              
5068 -                shortcutInfo.title = appInfo.title.toString();                                                    
5069 -                shortcut.applyFromShortcutInfo(shortcutInfo, mIconCache);                                         
5070 -            }                                                                                                     
5071 -        }                                                                                                         
5072 -    }                                                                                                             
5073 -                                                                                                                  
5074 -    void updateShortcuts(ArrayList<AppInfo> apps) {                                                               
5075 +    interface ItemOperator {                                                                                      
5076 +        /**                                                                                                       
5077 +         * Process the next itemInfo, possibly with side-effect on {@link ItemOperator#value}.                    
5078 +         *                                                                                                        
5079 +         * @param info info for the shortcut                                                                      
5080 +         * @param view view for the shortcut                                                                      
5081 +         * @param parent containing folder, or null                                                               
5082 +         * @return true if done, false to continue the map                                                        
5083 +         */                                                                                                       
5084 +        public boolean evaluate(ItemInfo info, View view, View parent);                                           
5085 +    }                                                                                                             
5086 +                                                                                                                  
5087 +    /**                                                                                                           
5088 +     * Map the operator over the shortcuts and widgets, return the first-non-null value.                          
5089 +     *                                                                                                            
5090 +     * @param recurse true: iterate over folder children. false: op get the folders themselves.                   
5091 +     * @param op the operator to map over the shortcuts                                                           
5092 +     */                                                                                                           
5093 +    void mapOverItems(boolean recurse, ItemOperator op) {                                                         
5094 +        ArrayList<ShortcutAndWidgetContainer> containers = getAllShortcutAndWidgetContainers();                   
5095 +        final int containerCount = containers.size();                                                             
5096 +        for (int containerIdx = 0; containerIdx < containerCount; containerIdx++) {                               
5097 +            ShortcutAndWidgetContainer container = containers.get(containerIdx);                                  
5098 +            // map over all the shortcuts on the workspace                                                        
5099 +            final int itemCount = container.getChildCount();                                                      
5100 +            for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) {                                               
5101 +                View item = container.getChildAt(itemIdx);                                                        
5102 +                ItemInfo info = (ItemInfo) item.getTag();                                                         
5103 +                if (recurse && info instanceof FolderInfo && item instanceof FolderIcon) {                        
5104 +                    FolderIcon folder = (FolderIcon) item;                                                        
5105 +                    ArrayList<View> folderChildren = folder.getFolder().getItemsInReadingOrder();                 
5106 +                    // map over all the children in the folder                                                    
5107 +                    final int childCount = folderChildren.size();                                                 
5108 +                    for (int childIdx = 0; childIdx < childCount; childIdx++) {                                   
5109 +                        View child = folderChildren.get(childIdx);                                                
5110 +                        info = (ItemInfo) child.getTag();                                                         
5111 +                        if (op.evaluate(info, child, folder)) {                                                   
5112 +                            return;                                                                               
5113 +                        }                                                                                         
5114 +                    }                                                                                             
5115 +                } else {                                                                                          
5116 +                    if (op.evaluate(info, item, null)) {                                                          
5117 +                        return;                                                                                   
5118 +                    }                                                                                             
5119 +                }                                                                                                 
5120 +            }                                                                                                     
5121 +        }                                                                                                         
5122 +    }                                                                                                             
5123 +                                                                                                                  
5124 +    void updateShortcutsAndWidgets(ArrayList<AppInfo> apps) {                                                     
5125 +        // Break the appinfo list per user                                                                        
5126 +        final HashMap<UserHandleCompat, ArrayList<AppInfo>> appsPerUser =                                         
5127 +                new HashMap<UserHandleCompat, ArrayList<AppInfo>>();                                              
5128 +        for (AppInfo info : apps) {                                                                               
5129 +            ArrayList<AppInfo> filtered = appsPerUser.get(info.user);                                             
5130 +            if (filtered == null) {                                                                               
5131 +                filtered = new ArrayList<AppInfo>();                                                              
5132 +                appsPerUser.put(info.user, filtered);                                                             
5133 +            }                                                                                                     
5134 +            filtered.add(info);                                                                                   
5135 +        }                                                                                                         
5136 +                                                                                                                  
5137 +        for (Map.Entry<UserHandleCompat, ArrayList<AppInfo>> entry : appsPerUser.entrySet()) {                    
5138 +            updateShortcutsAndWidgetsPerUser(entry.getValue(), entry.getKey());                                   
5139 +        }                                                                                                         
5140 +    }                                                                                                             
5141 +                                                                                                                  
5142 +    private void updateShortcutsAndWidgetsPerUser(ArrayList<AppInfo> apps,                                        
5143 +            final UserHandleCompat user) {                                                                        
5144          // Create a map of the apps to test against                                                               
5145          final HashMap<ComponentName, AppInfo> appsMap = new HashMap<ComponentName, AppInfo>();                    
5146 +        final HashSet<String> pkgNames = new HashSet<String>();                                                   
5147          for (AppInfo ai : apps) {                                                                                 
5148              appsMap.put(ai.componentName, ai);                                                                    
5149 -        }                                                                                                         
5150 -                                                                                                                  
5151 -        ArrayList<ShortcutAndWidgetContainer> childrenLayouts = getAllShortcutAndWidgetContainers();              
5152 -        for (ShortcutAndWidgetContainer layout: childrenLayouts) {                                                
5153 -            // Update all the children shortcuts                                                                  
5154 -            final HashMap<ItemInfo, View> children = new HashMap<ItemInfo, View>();                               
5155 -            for (int j = 0; j < layout.getChildCount(); j++) {                                                    
5156 -                View v = layout.getChildAt(j);                                                                    
5157 -                ItemInfo info = (ItemInfo) v.getTag();                                                            
5158 -                if (info instanceof FolderInfo && v instanceof FolderIcon) {                                      
5159 -                    FolderIcon folder = (FolderIcon) v;                                                           
5160 -                    ArrayList<View> folderChildren = folder.getFolder().getItemsInReadingOrder();                 
5161 -                    for (View fv : folderChildren) {                                                              
5162 -                        info = (ItemInfo) fv.getTag();                                                            
5163 -                        updateShortcut(appsMap, info, fv);                                                        
5164 +            pkgNames.add(ai.componentName.getPackageName());                                                      
5165 +        }                                                                                                         
5166 +        final HashSet<ComponentName> iconsToRemove = new HashSet<ComponentName>();                                
5167 +                                                                                                                  
5168 +        mapOverItems(MAP_RECURSE, new ItemOperator() {                                                            
5169 +            @Override                                                                                             
5170 +            public boolean evaluate(ItemInfo info, View v, View parent) {                                         
5171 +                if (info instanceof ShortcutInfo && v instanceof BubbleTextView) {                                
5172 +                    ShortcutInfo shortcutInfo = (ShortcutInfo) info;                                              
5173 +                    ComponentName cn = shortcutInfo.getTargetComponent();                                         
5174 +                    AppInfo appInfo = appsMap.get(cn);                                                            
5175 +                    if (user.equals(shortcutInfo.user) && cn != null                                              
5176 +                            && LauncherModel.isShortcutInfoUpdateable(info)                                       
5177 +                            && pkgNames.contains(cn.getPackageName())) {                                          
5178 +                        boolean promiseStateChanged = false;                                                      
5179 +                        boolean infoUpdated = false;                                                              
5180 +                        if (shortcutInfo.isPromise()) {                                                           
5181 +                            if (shortcutInfo.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {                  
5182 +                                // Auto install icon                                                              
5183 +                                PackageManager pm = getContext().getPackageManager();                             
5184 +                                ResolveInfo matched = pm.resolveActivity(                                         
5185 +                                        new Intent(Intent.ACTION_MAIN)                                            
5186 +                                        .setComponent(cn).addCategory(Intent.CATEGORY_LAUNCHER),                  
5187 +                                        PackageManager.MATCH_DEFAULT_ONLY);                                       
5188 +                                if (matched == null) {                                                            
5189 +                                    // Try to find the best match activity.                                       
5190 +                                    Intent intent = pm.getLaunchIntentForPackage(                                 
5191 +                                            cn.getPackageName());                                                 
5192 +                                    if (intent != null) {                                                         
5193 +                                        cn = intent.getComponent();                                               
5194 +                                        appInfo = appsMap.get(cn);                                                
5195 +                                    }                                                                             
5196 +                                                                                                                  
5197 +                                    if ((intent == null) || (appsMap == null)) {                                  
5198 +                                        // Could not find a default activity. Remove this item.                   
5199 +                                        iconsToRemove.add(shortcutInfo.getTargetComponent());                     
5200 +                                                                                                                  
5201 +                                        // process next shortcut.                                                 
5202 +                                        return false;                                                             
5203 +                                    }                                                                             
5204 +                                    shortcutInfo.promisedIntent = intent;                                         
5205 +                                }                                                                                 
5206 +                            }                                                                                     
5207 +                                                                                                                  
5208 +                            // Restore the shortcut.                                                              
5209 +                            shortcutInfo.intent = shortcutInfo.promisedIntent;                                    
5210 +                            shortcutInfo.promisedIntent = null;                                                   
5211 +                            shortcutInfo.status &= ~ShortcutInfo.FLAG_RESTORED_ICON                               
5212 +                                    & ~ShortcutInfo.FLAG_AUTOINTALL_ICON                                          
5213 +                                    & ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;                                  
5214 +                                                                                                                  
5215 +                            promiseStateChanged = true;                                                           
5216 +                            infoUpdated = true;                                                                   
5217 +                            shortcutInfo.updateIcon(mIconCache);                                                  
5218 +                            LauncherModel.updateItemInDatabase(getContext(), shortcutInfo);                       
5219 +                        }                                                                                         
5220 +                                                                                                                  
5221 +                                                                                                                  
5222 +                        if (appInfo != null) {                                                                    
5223 +                            shortcutInfo.updateIcon(mIconCache);                                                  
5224 +                            shortcutInfo.title = appInfo.title.toString();                                        
5225 +                            shortcutInfo.contentDescription = appInfo.contentDescription;                         
5226 +                            infoUpdated = true;                                                                   
5227 +                        }                                                                                         
5228 +                                                                                                                  
5229 +                        if (infoUpdated) {                                                                        
5230 +                            BubbleTextView shortcut = (BubbleTextView) v;                                         
5231 +                            shortcut.applyFromShortcutInfo(shortcutInfo,                                          
5232 +                                    mIconCache, true, promiseStateChanged);                                       
5233 +                                                                                                                  
5234 +                            if (parent != null) {                                                                 
5235 +                                parent.invalidate();                                                              
5236 +                            }                                                                                     
5237 +                        }                                                                                         
5238                      }                                                                                             
5239 -                    folder.invalidate();                                                                          
5240 -                } else if (info instanceof ShortcutInfo) {                                                        
5241 -                    updateShortcut(appsMap, info, v);                                                             
5242 -                }                                                                                                 
5243 +                }                                                                                                 
5244 +                // process all the shortcuts                                                                      
5245 +                return false;                                                                                     
5246 +            }                                                                                                     
5247 +        });                                                                                                       
5248 +                                                                                                                  
5249 +        if (!iconsToRemove.isEmpty()) {                                                                           
5250 +            removeItemsByComponentName(iconsToRemove, user);                                                      
5251 +        }                                                                                                         
5252 +        if (user.equals(UserHandleCompat.myUserHandle())) {                                                       
5253 +            restorePendingWidgets(pkgNames);                                                                      
5254 +        }                                                                                                         
5255 +    }                                                                                                             
5256 +                                                                                                                  
5257 +    public void removeAbandonedPromise(String packageName, UserHandleCompat user) {                               
5258 +        ArrayList<String> packages = new ArrayList<String>(1);                                                    
5259 +        packages.add(packageName);                                                                                
5260 +        LauncherModel.deletePackageFromDatabase(mLauncher, packageName, user);                                    
5261 +        removeItemsByPackageName(packages, user);                                                                 
5262 +    }                                                                                                             
5263 +                                                                                                                  
5264 +    public void updatePackageBadge(final String packageName, final UserHandleCompat user) {                       
5265 +        mapOverItems(MAP_RECURSE, new ItemOperator() {                                                            
5266 +            @Override                                                                                             
5267 +            public boolean evaluate(ItemInfo info, View v, View parent) {                                         
5268 +                if (info instanceof ShortcutInfo && v instanceof BubbleTextView) {                                
5269 +                    ShortcutInfo shortcutInfo = (ShortcutInfo) info;                                              
5270 +                    ComponentName cn = shortcutInfo.getTargetComponent();                                         
5271 +                    if (user.equals(shortcutInfo.user) && cn != null                                              
5272 +                            && shortcutInfo.isPromise()                                                           
5273 +                            && packageName.equals(cn.getPackageName())) {                                         
5274 +                        if (shortcutInfo.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {                      
5275 +                            // For auto install apps update the icon as well as label.                            
5276 +                            mIconCache.getTitleAndIcon(shortcutInfo,                                              
5277 +                                    shortcutInfo.promisedIntent, user, true);                                     
5278 +                        } else {                                                                                  
5279 +                            // Only update the icon for restored apps.                                            
5280 +                            shortcutInfo.updateIcon(mIconCache);                                                  
5281 +                        }                                                                                         
5282 +                        BubbleTextView shortcut = (BubbleTextView) v;                                             
5283 +                        shortcut.applyFromShortcutInfo(shortcutInfo, mIconCache, true, false);                    
5284 +                                                                                                                  
5285 +                        if (parent != null) {                                                                     
5286 +                            parent.invalidate();                                                                  
5287 +                        }                                                                                         
5288 +                    }                                                                                             
5289 +                }                                                                                                 
5290 +                // process all the shortcuts                                                                      
5291 +                return false;                                                                                     
5292 +            }                                                                                                     
5293 +        });                                                                                                       
5294 +    }                                                                                                             
5295 +                                                                                                                  
5296 +    public void updatePackageState(ArrayList<PackageInstallInfo> installInfos) {                                  
5297 +        HashSet<String> completedPackages = new HashSet<String>();                                                
5298 +                                                                                                                  
5299 +        for (final PackageInstallInfo installInfo : installInfos) {                                               
5300 +            mapOverItems(MAP_RECURSE, new ItemOperator() {                                                        
5301 +                @Override                                                                                         
5302 +                public boolean evaluate(ItemInfo info, View v, View parent) {                                     
5303 +                    if (info instanceof ShortcutInfo && v instanceof BubbleTextView) {                            
5304 +                        ShortcutInfo si = (ShortcutInfo) info;                                                    
5305 +                        ComponentName cn = si.getTargetComponent();                                               
5306 +                        if (si.isPromise() && (cn != null)                                                        
5307 +                                && installInfo.packageName.equals(cn.getPackageName())) {                         
5308 +                            si.setInstallProgress(installInfo.progress);                                          
5309 +                            if (installInfo.state == PackageInstallerCompat.STATUS_FAILED) {                      
5310 +                                // Mark this info as broken.                                                      
5311 +                                si.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;                           
5312 +                            }                                                                                     
5313 +                            ((BubbleTextView)v).applyState(false);                                                
5314 +                        }                                                                                         
5315 +                    } else if (v instanceof PendingAppWidgetHostView                                              
5316 +                            && info instanceof LauncherAppWidgetInfo                                              
5317 +                            && ((LauncherAppWidgetInfo) info).providerName.getPackageName()                       
5318 +                                .equals(installInfo.packageName)) {                                               
5319 +                        ((LauncherAppWidgetInfo) info).installProgress = installInfo.progress;                    
5320 +                        ((PendingAppWidgetHostView) v).applyState();                                              
5321 +                    }                                                                                             
5322 +                                                                                                                  
5323 +                    // process all the shortcuts                                                                  
5324 +                    return false;                                                                                 
5325 +                }                                                                                                 
5326 +            });                                                                                                   
5327 +                                                                                                                  
5328 +            if (installInfo.state == PackageInstallerCompat.STATUS_INSTALLED) {                                   
5329 +                completedPackages.add(installInfo.packageName);                                                   
5330 +            }                                                                                                     
5331 +        }                                                                                                         
5332 +                                                                                                                  
5333 +        // Note that package states are sent only for myUser                                                      
5334 +        if (!completedPackages.isEmpty()) {                                                                       
5335 +            restorePendingWidgets(completedPackages);                                                             
5336 +        }                                                                                                         
5337 +    }                                                                                                             
5338 +                                                                                                                  
5339 +    private void restorePendingWidgets(final Set<String> installedPackaged) {                                     
5340 +        final ArrayList<LauncherAppWidgetInfo> changedInfo = new ArrayList<LauncherAppWidgetInfo>();              
5341 +                                                                                                                  
5342 +        // Iterate non recursively as widgets can't be inside a folder.                                           
5343 +        mapOverItems(MAP_NO_RECURSE, new ItemOperator() {                                                         
5344 +                                                                                                                  
5345 +            @Override                                                                                             
5346 +            public boolean evaluate(ItemInfo info, View v, View parent) {                                         
5347 +                if (info instanceof LauncherAppWidgetInfo) {                                                      
5348 +                    LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info;                              
5349 +                    if (widgetInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)                  
5350 +                            && installedPackaged.contains(widgetInfo.providerName.getPackageName())) {            
5351 +                                                                                                                  
5352 +                        changedInfo.add(widgetInfo);                                                              
5353 +                                                                                                                  
5354 +                        // Remove the provider not ready flag                                                     
5355 +                        widgetInfo.restoreStatus &= ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;               
5356 +                        LauncherModel.updateItemInDatabase(getContext(), widgetInfo);                             
5357 +                    }                                                                                             
5358 +                }                                                                                                 
5359 +                // process all the widget                                                                         
5360 +                return false;                                                                                     
5361 +            }                                                                                                     
5362 +        });                                                                                                       
5363 +        if (!changedInfo.isEmpty()) {                                                                             
5364 +            DeferredWidgetRefresh widgetRefresh = new DeferredWidgetRefresh(changedInfo,                          
5365 +                    mLauncher.getAppWidgetHost());                                                                
5366 +            if (LauncherModel.findAppWidgetProviderInfoWithComponent(getContext(),                                
5367 +                    changedInfo.get(0).providerName) != null) {                                                   
5368 +                // Re-inflate the widgets which have changed status                                               
5369 +                widgetRefresh.run();                                                                              
5370 +            } else {                                                                                              
5371 +                // widgetRefresh will automatically run when the packages are updated.                            
5372              }                                                                                                     
5373          }                                                                                                         
5374      }                                                                                                             
5375                                                                                                                    
5376      private void moveToScreen(int page, boolean animate) {                                                        
5377 -        if (!isSmall()) {                                                                                         
5378 +        if (!workspaceInModalState()) {                                                                           
5379              if (animate) {                                                                                        
5380                  snapToPage(page);                                                                                 
5381              } else {                                                                                              
5382                  setCurrentPage(page);                                                                             
5383              }                                                                                                     
5384          }                                                                                                         
5385          View child = getChildAt(page);                                                                            
5386          if (child != null) {                                                                                      
5387              child.requestFocus();                                                                                 
5388          }                                                                                                         
5389      }                                                                                                             
5390                                                                                                                    
5391      void moveToDefaultScreen(boolean animate) {                                                                   
5392          moveToScreen(mDefaultPage, animate);                                                                      
5393      }                                                                                                             
5394                                                                                                                    
5395      void moveToCustomContentScreen(boolean animate) {                                                             
5396          if (hasCustomContent()) {                                                                                 
5397              int ccIndex = getPageIndexForScreenId(CUSTOM_CONTENT_SCREEN_ID);                                      
5398              if (animate) {                                                                                        
5399                  snapToPage(ccIndex);                                                                              
5400              } else {                                                                                              
5401                  setCurrentPage(ccIndex);                                                                          
5402              }                                                                                                     
5403              View child = getChildAt(ccIndex);                                                                     
5404              if (child != null) {                                                                                  
5405                  child.requestFocus();                                                                             
5406              }                                                                                                     
5407           }                                                                                                        
5408          exitWidgetResizeMode();                                                                                   
5409      }                                                                                                             
5410                                                                                                                    
5411      @Override                                                                                                     
5412      protected PageIndicator.PageMarkerResources getPageIndicatorMarker(int pageIndex) {                           
5413          long screenId = getScreenIdForPageIndex(pageIndex);                                                       
5414          if (screenId == EXTRA_EMPTY_SCREEN_ID) {                                                                  
5415              int count = mScreenOrder.size() - numCustomPages();                                                   
5416              if (count > 1) {                                                                                      
5417                  return new PageIndicator.PageMarkerResources(R.drawable.ic_pageindicator_current,                 
5418                          R.drawable.ic_pageindicator_add);                                                         
5419              }                                                                                                     
5420          }                                                                                                         
5421                                                                                                                    
5422          return super.getPageIndicatorMarker(pageIndex);                                                           
5423      }                                                                                                             
5424                                                                                                                    
5425      @Override                                                                                                     
5426      public void syncPages() {                                                                                     
5427      }                                                                                                             
5428                                                                                                                    
5429      @Override                                                                                                     
5430      public void syncPageItems(int page, boolean immediate) {                                                      
5431      }                                                                                                             
5432                                                                                                                    
5433      protected String getPageIndicatorDescription() {                                                              
5434          String settings = getResources().getString(R.string.settings_button_text);                                
5435          return getCurrentPageDescription() + ", " + settings;                                                     
5436      }                                                                                                             
5437                                                                                                                    
5438      protected String getCurrentPageDescription() {                                                                
5439          int page = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage;                                        
5440          int delta = numCustomPages();                                                                             
5441          if (hasCustomContent() && getNextPage() == 0) {                                                           
5442              return mCustomContentDescription;                                                                     
5443          }                                                                                                         
5444          return String.format(getContext().getString(R.string.workspace_scroll_format),                            
5445                  page + 1 - delta, getChildCount() - delta);                                                       
5446      }                                                                                                             
5447                                                                                                                    
5448      public void getLocationInDragLayer(int[] loc) {                                                               
5449          mLauncher.getDragLayer().getLocationInDragLayer(this, loc);                                               
5450      }                                                                                                             
5451 +                                                                                                                  
5452 +    /**                                                                                                           
5453 +     * Used as a workaround to ensure that the AppWidgetService receives the                                      
5454 +     * PACKAGE_ADDED broadcast before updating widgets.                                                           
5455 +     */                                                                                                           
5456 +    private class DeferredWidgetRefresh implements Runnable {                                                     
5457 +        private final ArrayList<LauncherAppWidgetInfo> mInfos;                                                    
5458 +        private final LauncherAppWidgetHost mHost;                                                                
5459 +        private final Handler mHandler;                                                                           
5460 +                                                                                                                  
5461 +        private boolean mRefreshPending;                                                                          
5462 +                                                                                                                  
5463 +        public DeferredWidgetRefresh(ArrayList<LauncherAppWidgetInfo> infos,                                      
5464 +                LauncherAppWidgetHost host) {                                                                     
5465 +            mInfos = infos;                                                                                       
5466 +            mHost = host;                                                                                         
5467 +            mHandler = new Handler();                                                                             
5468 +            mRefreshPending = true;                                                                               
5469 +                                                                                                                  
5470 +            mHost.addProviderChangeListener(this);                                                                
5471 +            // Force refresh after 10 seconds, if we don't get the provider changed event.                        
5472 +            // This could happen when the provider is no longer available in the app.                             
5473 +            mHandler.postDelayed(this, 10000);                                                                    
5474 +        }                                                                                                         
5475 +                                                                                                                  
5476 +        @Override                                                                                                 
5477 +        public void run() {                                                                                       
5478 +            mHost.removeProviderChangeListener(this);                                                             
5479 +            mHandler.removeCallbacks(this);                                                                       
5480 +                                                                                                                  
5481 +            if (!mRefreshPending) {                                                                               
5482 +                return;                                                                                           
5483 +            }                                                                                                     
5484 +                                                                                                                  
5485 +            mRefreshPending = false;                                                                              
5486 +                                                                                                                  
5487 +            for (LauncherAppWidgetInfo info : mInfos) {                                                           
5488 +                if (info.hostView instanceof PendingAppWidgetHostView) {                                          
5489 +                    PendingAppWidgetHostView view = (PendingAppWidgetHostView) info.hostView;                     
5490 +                    mLauncher.removeAppWidget(info);                                                              
5491 +                                                                                                                  
5492 +                    CellLayout cl = (CellLayout) view.getParent().getParent();                                    
5493 +                    // Remove the current widget                                                                  
5494 +                    cl.removeView(view);                                                                          
5495 +                    mLauncher.bindAppWidget(info);                                                                
5496 +                }                                                                                                 
5497 +            }                                                                                                     
5498 +        }                                                                                                         
5499 +    }                                                                                                             
5500  }